Commit 3b30a26c authored by Simon Morlat's avatar Simon Morlat

implement fix for IST, clean object memory handling

parent 45f88e5b
......@@ -24,6 +24,7 @@ typedef enum belle_sip_transaction_state{
BELLE_SIP_TRANSACTION_CALLING,
BELLE_SIP_TRANSACTION_COMPLETED,
BELLE_SIP_TRANSACTION_CONFIRMED,
BELLE_SIP_TRANSACTION_ACCEPTED, /*<for Invite transaction, introduced by RFC6026, fixing bugs in RFC3261*/
BELLE_SIP_TRANSACTION_PROCEEDING,
BELLE_SIP_TRANSACTION_TRYING,
BELLE_SIP_TRANSACTION_TERMINATED
......
......@@ -389,7 +389,7 @@ belle_sip_##object_type##_t* belle_sip_##object_type##_parse (const char* value)
, belle_sip_##super_type##_t\
, belle_sip_##object_type##_destroy\
, belle_sip_##object_type##_clone\
, belle_sip_##object_type##_marshal, FALSE); \
, belle_sip_##object_type##_marshal, TRUE); \
belle_sip_##object_type##_t* belle_sip_##object_type##_new () { \
belle_sip_##object_type##_t* l_object = belle_sip_object_new(belle_sip_##object_type##_t);\
belle_sip_##super_type##_init((belle_sip_##super_type##_t*)l_object); \
......@@ -634,6 +634,7 @@ struct belle_sip_ist{
belle_sip_source_t *timer_G;
belle_sip_source_t *timer_H;
belle_sip_source_t *timer_I;
belle_sip_source_t *timer_L;
};
typedef struct belle_sip_ist belle_sip_ist_t;
......@@ -642,7 +643,8 @@ BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_ist_t,belle_sip_server_transaction
BELLE_SIP_DECLARE_CUSTOM_VPTR_END
belle_sip_ist_t * belle_sip_ist_new(belle_sip_provider_t *prov, belle_sip_request_t *req);
void belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack);
/* returns 0 if the ack should be notified to TU, or -1 otherwise*/
int belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack);
struct belle_sip_nist{
belle_sip_server_transaction_t base;
......@@ -679,7 +681,7 @@ struct belle_sip_dialog{
int is_server:1;
int is_secure:1;
int terminate_on_bye:1;
int needs_ack;
int needs_ack:1;
};
belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t);
......@@ -688,6 +690,7 @@ int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const
int belle_sip_dialog_match(belle_sip_dialog_t *obj, belle_sip_message_t *msg, int as_uas);
int belle_sip_dialog_update(belle_sip_dialog_t *obj,belle_sip_request_t *req, belle_sip_response_t *resp, int as_uas);
void belle_sip_dialog_check_ack_sent(belle_sip_dialog_t*obj);
int belle_sip_dialog_handle_ack(belle_sip_dialog_t *obj, belle_sip_request_t *ack);
/*
belle_sip_response_t
*/
......
......@@ -51,13 +51,15 @@ belle_sip_object_t * belle_sip_object_ref(void *obj){
void belle_sip_object_unref(void *ptr){
belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
if (obj->ref==-1) belle_sip_fatal("Object freed twice !");
if (obj->ref==0){
/*might hide a double unref belle_sip_warning("Destroying unowed object");*/
obj->ref=-1;
belle_sip_object_delete(obj);
return;
}
obj->ref--;
if (obj->ref==0){
obj->ref=-1;
belle_sip_object_delete(obj);
}
}
......@@ -86,6 +88,7 @@ void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t de
for(ref=o->weak_refs;ref!=NULL;ref=next){
next=ref->next;
if (ref->notify==destroy_notify && ref->userpointer==userpointer){
belle_sip_message("belle_sip_object_weak_unref(): prefref=%p",prevref);
if (prevref==NULL) o->weak_refs=next;
else prevref->next=next;
belle_sip_free(ref);
......@@ -135,10 +138,6 @@ void belle_sip_object_delete(void *ptr){
belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
belle_sip_object_vptr_t *vptr;
if (obj->ref!=0){
belle_sip_error("Destroying referenced object !");
}
obj->ref=-1;
belle_sip_object_loose_weak_refs(obj);
vptr=obj->vptr;
while(vptr!=NULL){
......
......@@ -39,10 +39,22 @@ const char *belle_sip_channel_state_to_string(belle_sip_channel_state_t state){
return "BAD";
}
static belle_sip_list_t * for_each_weak_unref_free(belle_sip_list_t *l, belle_sip_object_destroy_notify_t notify, void *ptr){
belle_sip_list_t *elem,*next;
for(elem=l;elem!=NULL;elem=next){
next=elem->next;
belle_sip_object_weak_unref(elem->data,notify,ptr);
belle_sip_free(elem);
}
return NULL;
}
static void belle_sip_channel_destroy(belle_sip_channel_t *obj){
if (obj->peer) freeaddrinfo(obj->peer);
belle_sip_free(obj->peer_name);
if (obj->local_ip) belle_sip_free(obj->local_ip);
obj->listeners=for_each_weak_unref_free(obj->listeners,(belle_sip_object_destroy_notify_t)belle_sip_channel_remove_listener,obj);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_channel_t);
......
......@@ -201,6 +201,18 @@ int belle_sip_dialog_establish(belle_sip_dialog_t *obj, belle_sip_request_t *req
return 0;
}
int belle_sip_dialog_check_incoming_request_ordering(belle_sip_dialog_t *obj, belle_sip_request_t *req){
belle_sip_header_cseq_t *cseqh=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
unsigned int cseq=belle_sip_header_cseq_get_seq_number(cseqh);
if (obj->remote_cseq==0){
obj->remote_cseq=cseq;
}else if (cseq>obj->remote_cseq){
return 0;
}
belle_sip_warning("Ignoring request because cseq is inconsistent.");
return -1;
}
int belle_sip_dialog_update(belle_sip_dialog_t *obj,belle_sip_request_t *req, belle_sip_response_t *resp, int as_uas){
int code;
switch (obj->state){
......@@ -437,3 +449,13 @@ void belle_sip_dialog_handle_200Ok(belle_sip_dialog_t *obj, belle_sip_message_t
}
}
}
int belle_sip_dialog_handle_ack(belle_sip_dialog_t *obj, belle_sip_request_t *ack){
belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(ack,belle_sip_header_cseq_t);
if (obj->needs_ack && belle_sip_header_cseq_get_seq_number(cseq)==obj->remote_cseq){
belle_sip_message("Incoming INVITE has ACK, dialog is happy");
obj->needs_ack=FALSE;
return 0;
}
return -1;
}
......@@ -52,6 +52,7 @@ static belle_sip_request_t *make_ack(belle_sip_ict_t *obj, belle_sip_response_t
belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
if (obj->ack==NULL){
obj->ack=belle_sip_request_new();
belle_sip_object_ref(obj->ack);
belle_sip_request_set_method(obj->ack,"ACK");
belle_sip_request_set_uri(obj->ack,belle_sip_request_get_uri(base->request));
belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_VIA,FALSE);
......
......@@ -40,6 +40,10 @@ static void ist_on_terminate(belle_sip_ist_t *obj){
belle_sip_transaction_stop_timer(base,obj->timer_I);
belle_sip_object_unref(obj->timer_I);
}
if (obj->timer_L){
belle_sip_transaction_stop_timer(base,obj->timer_L);
belle_sip_object_unref(obj->timer_L);
}
}
static int ist_on_timer_G(belle_sip_ist_t *obj){
......@@ -70,22 +74,37 @@ static int ist_on_timer_I(belle_sip_ist_t *obj){
return BELLE_SIP_STOP;
}
void belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack){
static int ist_on_timer_L(belle_sip_ist_t *obj){
belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
if (base->state==BELLE_SIP_TRANSACTION_COMPLETED){
/*clear timer G*/
if (obj->timer_G){
belle_sip_transaction_stop_timer(base,obj->timer_G);
belle_sip_object_unref(obj->timer_G);
obj->timer_G=NULL;
}
base->state=BELLE_SIP_TRANSACTION_CONFIRMED;
if (!belle_sip_channel_is_reliable(base->channel)){
const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
obj->timer_I=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_I,obj,cfg->T4);
belle_sip_transaction_start_timer(base,obj->timer_I);
}else ist_on_timer_I(obj);
belle_sip_transaction_terminate(base);
return BELLE_SIP_STOP;
}
int belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack){
belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
int ret=-1;
switch(base->state){
case BELLE_SIP_TRANSACTION_COMPLETED:
/*clear timer G*/
if (obj->timer_G){
belle_sip_transaction_stop_timer(base,obj->timer_G);
belle_sip_object_unref(obj->timer_G);
obj->timer_G=NULL;
}
base->state=BELLE_SIP_TRANSACTION_CONFIRMED;
if (!belle_sip_channel_is_reliable(base->channel)){
const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
obj->timer_I=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_I,obj,cfg->T4);
belle_sip_transaction_start_timer(base,obj->timer_I);
}else ist_on_timer_I(obj);
break;
case BELLE_SIP_TRANSACTION_ACCEPTED:
ret=0; /*let the ACK be reported to TU */
break;
default:
break;
}
return ret;
}
static int ist_send_new_response(belle_sip_ist_t *obj, belle_sip_response_t *resp){
......@@ -94,21 +113,29 @@ static int ist_send_new_response(belle_sip_ist_t *obj, belle_sip_response_t *res
int ret=-1;
switch(base->state){
case BELLE_SIP_TRANSACTION_PROCEEDING:
ret=0;
belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)resp);
if (code>=200 && code<300)
belle_sip_transaction_terminate(base);
else if (code>=300){
{
const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
base->state=BELLE_SIP_TRANSACTION_COMPLETED;
if (!belle_sip_channel_is_reliable(base->channel)){
obj->timer_G=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_G,obj,cfg->T1);
belle_sip_transaction_start_timer(base,obj->timer_G);
ret=0;
belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)resp);
if (code>=200 && code<300){
base->state=BELLE_SIP_TRANSACTION_ACCEPTED;
obj->timer_L=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_L,obj,64*cfg->T1);
belle_sip_transaction_start_timer(base,obj->timer_L);
}else if (code>=300){
base->state=BELLE_SIP_TRANSACTION_COMPLETED;
if (!belle_sip_channel_is_reliable(base->channel)){
obj->timer_G=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_G,obj,cfg->T1);
belle_sip_transaction_start_timer(base,obj->timer_G);
}
obj->timer_H=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_H,obj,64*cfg->T1);
belle_sip_transaction_start_timer(base,obj->timer_H);
}
obj->timer_H=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_H,obj,64*cfg->T1);
belle_sip_transaction_start_timer(base,obj->timer_H);
}
break;
case BELLE_SIP_TRANSACTION_ACCEPTED:
if (code>=200 && code<300){
ret=0; /*let the response go to transport layer*/
}
default:
break;
}
......@@ -156,6 +183,5 @@ belle_sip_ist_t *belle_sip_ist_new(belle_sip_provider_t *prov, belle_sip_request
base->state=BELLE_SIP_TRANSACTION_PROCEEDING;
resp=belle_sip_response_create_from_request(req,100);
belle_sip_server_transaction_send_response((belle_sip_server_transaction_t*)obj,resp);
belle_sip_object_unref(resp);
return obj;
}
......@@ -45,8 +45,9 @@ struct _belle_sip_message {
};
static void belle_sip_message_destroy(belle_sip_message_t *msg){
belle_sip_list_for_each (msg->header_list,(void (*)(void*))belle_sip_headers_container_delete);
belle_sip_list_free(msg->header_list);
belle_sip_list_free_with_data(msg->header_list,(void (*)(void*))belle_sip_headers_container_delete);
if (msg->body)
belle_sip_free(msg->body);
}
/*very sub-optimal clone method */
......@@ -65,7 +66,7 @@ static void belle_sip_message_clone(belle_sip_message_t *obj, const belle_sip_me
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_message_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_message_t,belle_sip_object_t,belle_sip_message_destroy,belle_sip_message_clone,NULL,FALSE);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_message_t,belle_sip_object_t,belle_sip_message_destroy,belle_sip_message_clone,NULL,TRUE);
belle_sip_message_t* belle_sip_message_parse (const char* value) {
size_t message_length;
......
......@@ -23,6 +23,8 @@
static void belle_sip_provider_uninit(belle_sip_provider_t *p){
belle_sip_list_free(p->listeners);
belle_sip_list_free_with_data(p->lps,belle_sip_object_unref);
belle_sip_list_free_with_data(p->client_transactions,belle_sip_object_unref);
belle_sip_list_free_with_data(p->server_transactions,belle_sip_object_unref);
}
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
......@@ -127,7 +129,8 @@ static void belle_sip_provider_read_message(belle_sip_provider_t *prov, belle_si
*/
static int channel_on_event(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, unsigned int revents){
if (revents & BELLE_SIP_EVENT_READ){
belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),belle_sip_channel_pick_message(chan));
belle_sip_message_t *msg=(belle_sip_message_t*)belle_sip_object_ref(belle_sip_channel_pick_message(chan));
belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
}
return 0;
}
......@@ -245,19 +248,27 @@ belle_sip_dialog_t * belle_sip_provider_create_dialog(belle_sip_provider_t *prov
belle_sip_dialog_t *belle_sip_provider_find_dialog(belle_sip_provider_t *prov, belle_sip_request_t *msg, int as_uas){
belle_sip_list_t *elem;
belle_sip_dialog_t *dialog;
belle_sip_header_call_id_t *call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t);
belle_sip_header_call_id_t *call_id;
belle_sip_header_from_t *from;
belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t);
const char *from_tag;
const char *to_tag;
const char *call_id_value;
const char *local_tag,*remote_tag;
if (to==NULL || (to_tag=belle_sip_header_to_get_tag(to))==NULL){
/* a request without to tag cannot be part of a dialog */
return NULL;
}
call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t);
if (call_id==NULL || from==NULL || to==NULL) return NULL;
if (call_id==NULL || from==NULL) return NULL;
call_id_value=belle_sip_header_call_id_get_call_id(call_id);
from_tag=belle_sip_header_from_get_tag(from);
to_tag=belle_sip_header_to_get_tag(to);
local_tag=as_uas ? to_tag : from_tag;
remote_tag=as_uas ? from_tag : to_tag;
......@@ -280,13 +291,16 @@ void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dial
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
const char *method=belle_sip_request_get_method(req);
belle_sip_client_transaction_t *t;
if (strcmp(method,"INVITE")==0)
return (belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
else if (strcmp(method,"ACK")==0){
belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
return NULL;
}
else return (belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
else t=(belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
t->base.dialog=belle_sip_provider_find_dialog(prov,req,FALSE);
return t;
}
belle_sip_server_transaction_t *belle_sip_provider_create_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
......@@ -295,6 +309,7 @@ belle_sip_server_transaction_t *belle_sip_provider_create_server_transaction(bel
t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
else
t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
t->base.dialog=belle_sip_provider_find_dialog(prov,req,TRUE);
belle_sip_provider_add_server_transaction(prov,t);
return t;
}
......
......@@ -102,7 +102,7 @@ BELLE_SIP_IMPLEMENT_INTERFACE_END
BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_callbacks_t,belle_sip_listener_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_callbacks_t,belle_sip_object_t,NULL,NULL,NULL,FALSE);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_callbacks_t,belle_sip_object_t,NULL,NULL,NULL,TRUE);
belle_sip_listener_t *belle_sip_listener_create_from_callbacks(const belle_sip_listener_callbacks_t *callbacks, void *user_ctx){
......
......@@ -30,6 +30,8 @@ const char *belle_sip_transaction_state_to_string(belle_sip_transaction_state_t
return "COMPLETED";
case BELLE_SIP_TRANSACTION_CONFIRMED:
return "CONFIRMED";
case BELLE_SIP_TRANSACTION_ACCEPTED:
return "ACCEPTED";
case BELLE_SIP_TRANSACTION_PROCEEDING:
return "PROCEEDING";
case BELLE_SIP_TRANSACTION_TERMINATED:
......@@ -158,25 +160,33 @@ void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *
belle_sip_dialog_update(dialog,base->request,resp,TRUE);
}
static void server_transaction_notify(belle_sip_server_transaction_t *t, belle_sip_request_t *req, belle_sip_dialog_t *dialog){
belle_sip_request_event_t event;
event.source=t->base.provider;
event.server_transaction=t;
event.dialog=dialog;
event.request=req;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(t->base.provider,process_request_event,&event);
}
void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){
const char *method=belle_sip_request_get_method(req);
if (strcmp(method,"ACK")==0){
/*this must be for an INVITE server transaction */
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_ist_t)){
belle_sip_ist_t *ist=(belle_sip_ist_t*)t;
belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req);
if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
belle_sip_dialog_t *dialog=t->base.dialog;
if (dialog && belle_sip_dialog_handle_ack(dialog,req)==-1)
dialog=NULL;
server_transaction_notify(t,req,dialog);
}
}else{
belle_sip_warning("ACK received for non-invite server transaction ?");
}
}else if (strcmp(method,"CANCEL")==0){
/*just notify the application */
belle_sip_request_event_t event;
event.source=t->base.provider;
event.server_transaction=t;
event.dialog=t->base.dialog;
event.request=req;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(t->base.provider,process_request_event,&event);
server_transaction_notify(t,req,t->base.dialog);
}else
BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
}
......
......@@ -89,7 +89,7 @@ int register_init(void) {
stack=belle_sip_stack_new(NULL);
belle_sip_listening_point_t *lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"UDP");
prov=belle_sip_stack_create_provider(stack,lp);
belle_sip_object_unref(lp);
lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"TCP");
belle_sip_provider_add_listening_point(prov,lp);
belle_sip_object_unref(lp);
......@@ -136,7 +136,7 @@ belle_sip_request_t* register_user(belle_sip_stack_t * stack
,const char *transport
,int use_transaction
,const char* username) {
belle_sip_request_t *req;
belle_sip_request_t *req,*copy;
char identity[256];
char uri[256];
......@@ -159,11 +159,11 @@ belle_sip_request_t* register_user(belle_sip_stack_t * stack
belle_sip_header_to_create2(identity,NULL),
belle_sip_header_via_new(),
70);
is_register_ok=0;
using_transaction=0;
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_contact_new()));
copy=(belle_sip_request_t*)belle_sip_object_clone((belle_sip_object_t*)req);
belle_sip_provider_add_sip_listener(prov,l=BELLE_SIP_LISTENER(listener));
if (use_transaction){
belle_sip_client_transaction_t *t=belle_sip_provider_create_client_transaction(prov,req);
......@@ -175,7 +175,7 @@ belle_sip_request_t* register_user(belle_sip_stack_t * stack
belle_sip_provider_remove_sip_listener(prov,l);
return req;
return copy;
}
static void register_test(const char *transport, int use_transaction) {
......
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