Commit 6c838542 authored by jehan's avatar jehan
Browse files

Merge branch 'master' of gitosis@git.linphone.org:belle-sip

parents 8a8c3b54 ae734607
......@@ -442,6 +442,7 @@ struct _belle_sip_header {
void belle_sip_header_set_next(belle_sip_header_t* header,belle_sip_header_t* next);
belle_sip_header_t* belle_sip_header_get_next(const belle_sip_header_t* headers);
void belle_sip_response_fill_for_dialog(belle_sip_response_t *obj, belle_sip_request_t *req);
void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple);
void belle_sip_header_init(belle_sip_header_t* obj);
......@@ -494,6 +495,7 @@ struct belle_sip_provider{
belle_sip_list_t *listeners;
belle_sip_list_t *client_transactions;
belle_sip_list_t *server_transactions;
belle_sip_list_t *dialogs;
};
belle_sip_provider_t *belle_sip_provider_new(belle_sip_stack_t *s, belle_sip_listening_point_t *lp);
......@@ -506,6 +508,9 @@ belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transac
void belle_sip_provider_remove_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t);
void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t);
belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const char *name, int port, const char *transport);
void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog);
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog);
typedef struct listener_ctx{
belle_sip_listener_t *listener;
......@@ -657,6 +662,9 @@ belle_sip_nist_t * belle_sip_nist_new(belle_sip_provider_t *prov, belle_sip_requ
*/
struct belle_sip_dialog{
belle_sip_object_t base;
belle_sip_provider_t *provider;
belle_sip_request_t *last_out_invite;
belle_sip_request_t *last_out_ack; /*so that it can retransmitted when needed*/
belle_sip_dialog_state_t state;
void *appdata;
belle_sip_header_call_id_t *call_id;
......@@ -671,10 +679,15 @@ struct belle_sip_dialog{
int is_server:1;
int is_secure:1;
int terminate_on_bye:1;
int needs_ack;
};
belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t);
/*returns 1 if message belongs to the dialog, 0 otherwise */
int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const char *local_tag, const char *remote_tag);
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);
/*
belle_sip_response_t
*/
......
......@@ -34,6 +34,10 @@ static void belle_sip_dialog_uninit(belle_sip_dialog_t *obj){
belle_sip_free(obj->local_tag);
if (obj->remote_tag)
belle_sip_free(obj->remote_tag);
if (obj->last_out_invite)
belle_sip_object_unref(obj->last_out_invite);
if (obj->last_out_ack)
belle_sip_object_unref(obj->last_out_ack);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_dialog_t);
......@@ -110,6 +114,12 @@ static int belle_sip_dialog_init_as_uas(belle_sip_dialog_t *obj, belle_sip_reque
return 0;
}
static void set_last_out_invite(belle_sip_dialog_t *obj, belle_sip_request_t *req){
if (obj->last_out_invite)
belle_sip_object_unref(obj->last_out_invite);
obj->last_out_invite=(belle_sip_request_t*)belle_sip_object_ref(req);
}
static int belle_sip_dialog_init_as_uac(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){
const belle_sip_list_t *elem;
belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t);
......@@ -154,6 +164,9 @@ static int belle_sip_dialog_init_as_uac(belle_sip_dialog_t *obj, belle_sip_reque
/*local_tag is already set*/
obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(to);
/*local party is already set*/
if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
set_last_out_invite(obj,req);
}
return 0;
}
......@@ -182,6 +195,7 @@ int belle_sip_dialog_establish(belle_sip_dialog_t *obj, belle_sip_request_t *req
set_to_tag(obj,to);
if (belle_sip_dialog_establish_full(obj,req,resp)==0){
obj->state=BELLE_SIP_DIALOG_CONFIRMED;
obj->needs_ack=TRUE;
}else return -1;
}
return 0;
......@@ -201,12 +215,14 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj,belle_sip_request_t *req, be
if (as_uas){
ct=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t);
}else{
set_last_out_invite(obj,req);
ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t);
}
if (ct){
belle_sip_object_unref(obj->remote_target);
obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct);
}
obj->needs_ack=TRUE;
}else if (strcmp(belle_sip_request_get_method(req),"INVITE")==0 && code>=200 && code<300){
if (obj->terminate_on_bye) belle_sip_dialog_delete(obj);
}
......@@ -223,13 +239,6 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){
belle_sip_header_from_t *from;
const char *from_tag;
if (t->last_response){
int code=belle_sip_response_get_status_code(t->last_response);
if (code>=200 && code<300){
belle_sip_fatal("You must not create dialog after sending the response that establish the dialog.");
}
return NULL;
}
from=belle_sip_message_get_header_by_type(t->request,belle_sip_header_from_t);
if (from==NULL){
belle_sip_error("belle_sip_dialog_new(): no from!");
......@@ -242,6 +251,7 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){
}
obj=belle_sip_object_new(belle_sip_dialog_t);
obj->terminate_on_bye=1;
obj->provider=t->provider;
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)){
obj->remote_tag=belle_sip_strdup(from_tag);
......@@ -256,24 +266,52 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){
return obj;
}
belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *dialog, unsigned int cseq);
belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *obj, unsigned int cseq){
belle_sip_header_cseq_t *cseqh;
belle_sip_request_t *invite=obj->last_out_invite;
belle_sip_request_t *ack;
if (!invite){
belle_sip_error("No INVITE to ACK.");
return NULL;
}
cseqh=belle_sip_message_get_header_by_type(invite,belle_sip_header_cseq_t);
if (belle_sip_header_cseq_get_seq_number(cseqh)!=cseq){
belle_sip_error("No INVITE with cseq %i to create ack for.",cseq);
return NULL;
}
ack=belle_sip_dialog_create_request(obj,"ACK");
if (ack){
const belle_sip_list_t *aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Authorization");
const belle_sip_list_t *prx_aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Proxy-Authorization");
if (aut)
belle_sip_message_add_headers((belle_sip_message_t*)ack,aut);
if (prx_aut)
belle_sip_message_add_headers((belle_sip_message_t*)ack,prx_aut);
}
return ack;
}
belle_sip_request_t *belle_sip_dialog_create_request(belle_sip_dialog_t *obj, const char *method){
if (obj->local_cseq==0) obj->local_cseq=110;
belle_sip_request_t *req=belle_sip_request_create(belle_sip_header_address_get_uri(obj->remote_target),
method,
obj->call_id,
belle_sip_header_cseq_create(obj->local_cseq++,method),
belle_sip_header_cseq_create(obj->local_cseq,method),
belle_sip_header_from_create(obj->local_party,NULL),
belle_sip_header_to_create(obj->remote_party,NULL),
belle_sip_header_via_new(),
0);
belle_sip_message_add_headers((belle_sip_message_t*)req,obj->route_set);
if (strcmp(method,"ACK")!=0) obj->local_cseq++;
return req;
}
void belle_sip_dialog_delete(belle_sip_dialog_t *obj){
belle_sip_dialog_state_t prevstate=obj->state;
obj->state=BELLE_SIP_DIALOG_TERMINATED;
if (prevstate!=BELLE_SIP_DIALOG_NULL)
belle_sip_provider_remove_dialog(obj->provider,obj);
}
void *belle_sip_get_application_data(const belle_sip_dialog_t *dialog){
......@@ -336,8 +374,52 @@ int belle_sip_dialog_is_secure(const belle_sip_dialog_t *dialog){
return dialog->is_secure;
}
void belle_sip_dialog_send_ack(belle_sip_dialog_t *dialog, belle_sip_request_t *request);
void belle_sip_dialog_send_ack(belle_sip_dialog_t *obj, belle_sip_request_t *request){
if (obj->needs_ack){
obj->needs_ack=FALSE;
if (obj->last_out_ack)
belle_sip_object_unref(obj->last_out_ack);
obj->last_out_ack=(belle_sip_request_t*)belle_sip_object_ref(request);
belle_sip_provider_send_request(obj->provider,request);
}else{
belle_sip_error("Why do you want to send an ACK ?");
}
}
void belle_sip_dialog_terminate_on_bye(belle_sip_dialog_t *obj, int val){
obj->terminate_on_bye=val;
}
/*returns 1 if message belongs to the dialog, 0 otherwise */
int belle_sip_dialog_match(belle_sip_dialog_t *obj, belle_sip_message_t *msg, int as_uas){
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_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;
if (call_id==NULL || from==NULL || to==NULL) return 0;
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);
return _belle_sip_dialog_match(obj,call_id_value,as_uas ? to_tag : from_tag, as_uas ? from_tag : to_tag);
}
int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const char *local_tag, const char *remote_tag){
const char *dcid=belle_sip_header_call_id_get_call_id(obj->call_id);
if (obj->state==BELLE_SIP_DIALOG_NULL) belle_sip_fatal("_belle_sip_dialog_match() must not be used for dialog in null state.");
return strcmp(dcid,call_id)==0 && strcmp(obj->local_tag,local_tag)==0 && strcmp(obj->remote_tag,remote_tag)==0;
}
void belle_sip_dialog_check_ack_sent(belle_sip_dialog_t*obj){
if (obj->needs_ack){
belle_sip_request_t *req;
belle_sip_error("Your listener did not ACK'd the 200Ok for your INVITE request. The dialog will be terminated.");
req=belle_sip_dialog_create_request(obj,"BYE");
belle_sip_client_transaction_send_request(
belle_sip_provider_create_client_transaction(obj->provider,req));
}
}
......@@ -479,6 +479,18 @@ belle_sip_response_t *belle_sip_response_create_from_request(belle_sip_request_t
return resp;
}
void belle_sip_response_fill_for_dialog(belle_sip_response_t *obj, belle_sip_request_t *req){
const belle_sip_list_t *rr=belle_sip_message_get_headers((belle_sip_message_t*)req,BELLE_SIP_RECORD_ROUTE);
belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(obj,belle_sip_header_contact_t);
belle_sip_message_remove_header((belle_sip_message_t*)obj,BELLE_SIP_RECORD_ROUTE);
if (rr)
belle_sip_message_add_headers((belle_sip_message_t*)obj,rr);
if (!ct){
/*add a dummy contact to be filled by channel later*/
belle_sip_message_add_header((belle_sip_message_t*)obj,(belle_sip_header_t*)belle_sip_header_contact_new());
}
}
void belle_sip_response_get_return_hop(belle_sip_response_t *msg, belle_sip_hop_t *hop){
belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header(BELLE_SIP_MESSAGE(msg),"via"));
const char *host;
......
......@@ -226,11 +226,57 @@ belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_p
belle_sip_dialog_t * belle_sip_provider_create_dialog(belle_sip_provider_t *prov, belle_sip_transaction_t *t){
belle_sip_dialog_t *dialog=NULL;
if (t->last_response){
int code=belle_sip_response_get_status_code(t->last_response);
if (code>=200 && code<300){
belle_sip_fatal("You must not create dialog after sending the response that establish the dialog.");
}
return NULL;
}
dialog=belle_sip_dialog_new(t);
t->dialog=(belle_sip_dialog_t*)belle_sip_object_ref(dialog);
if (dialog)
t->dialog=(belle_sip_dialog_t*)belle_sip_object_ref(dialog);
return dialog;
}
/*finds an existing dialog for an outgoing or incoming request */
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_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 (call_id==NULL || from==NULL || to==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;
for (elem=prov->dialogs;elem!=NULL;elem=elem->next){
dialog=(belle_sip_dialog_t*)elem->data;
if (_belle_sip_dialog_match(dialog,call_id_value,local_tag,remote_tag))
return dialog;
}
return NULL;
}
void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
prov->dialogs=belle_sip_list_prepend(prov->dialogs,belle_sip_object_ref(dialog));
}
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
belle_sip_object_unref(dialog);
}
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);
if (strcmp(method,"INVITE")==0)
......
......@@ -126,6 +126,9 @@ void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");
belle_sip_dialog_t *dialog=base->dialog;
int status_code;
belle_sip_object_ref(resp);
if (!base->last_response){
belle_sip_hop_t hop;
......@@ -134,15 +137,25 @@ void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *
belle_sip_object_ref(base->channel);
belle_sip_hop_free(&hop);
}
if (belle_sip_header_to_get_tag(to)==NULL && belle_sip_response_get_status_code(resp)!=100){
//add a random to tag
belle_sip_header_to_set_tag(to,t->to_tag);
status_code=belle_sip_response_get_status_code(resp);
if (status_code!=100){
if (belle_sip_header_to_get_tag(to)==NULL){
//add a random to tag
belle_sip_header_to_set_tag(to,t->to_tag);
}
if (dialog && status_code>=200 && status_code<300){
/*response establishes a dialog*/
/*fill dialog related fields accordingly*/
belle_sip_response_fill_for_dialog(resp,base->request);
}
}
if (BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->send_new_response(t,resp)==0){
if (base->last_response)
belle_sip_object_unref(base->last_response);
base->last_response=resp;
}
if (dialog)
belle_sip_dialog_update(dialog,base->request,resp,TRUE);
}
void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){
......@@ -161,7 +174,7 @@ void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t,
event.source=t->base.provider;
event.server_transaction=t;
event.dialog=NULL;
event.dialog=t->base.dialog;
event.request=req;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(t->base.provider,process_request_event,&event);
}else
......@@ -232,16 +245,31 @@ void belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t
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;
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){
/*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);
if (dialog){
belle_sip_message("Handling response creating a new dialog !");
}
}
}
if (dialog) belle_sip_dialog_update(dialog,base->request,resp,FALSE);
}
event.source=base->provider;
event.client_transaction=t;
event.dialog=NULL;
event.dialog=dialog;
event.response=(belle_sip_response_t*)resp;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(base->provider,process_response_event,&event);
/*check that 200Ok for INVITEs have been acknoledged by listener*/
if (dialog) belle_sip_dialog_check_ack_sent(dialog);
}
......
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