static void set_to_tag(belle_sip_dialog_t *obj, belle_sip_header_to_t *to){ const char *to_tag=belle_sip_header_to_get_tag(to); if (obj->is_server){ if (to_tag && !obj->local_tag) obj->local_tag=belle_sip_strdup(to_tag); }else{ if (to_tag && !obj->remote_tag) obj->remote_tag=belle_sip_strdup(to_tag); } }
belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){ belle_sip_dialog_t *obj; belle_sip_header_from_t *from; const char *from_tag; belle_sip_header_to_t *to; const char *to_tag=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!"); return NULL; } from_tag=belle_sip_header_from_get_tag(from); if (from_tag==NULL){ belle_sip_error("belle_sip_dialog_new(): no from tag!"); return NULL; } if (t->last_response) { to=belle_sip_message_get_header_by_type(t->last_response,belle_sip_header_to_t); if (to==NULL){ belle_sip_error("belle_sip_dialog_new(): no to!"); return NULL; } to_tag=belle_sip_header_to_get_tag(to); } 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); obj->local_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=TRUE; }else{ const belle_sip_list_t *predefined_routes=NULL; obj->local_tag=belle_sip_strdup(from_tag); obj->remote_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=FALSE; for(predefined_routes=belle_sip_message_get_headers((belle_sip_message_t*)t->request,BELLE_SIP_ROUTE); predefined_routes!=NULL;predefined_routes=predefined_routes->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(predefined_routes->data)); } } belle_sip_message("New %s dialog [%p] , local tag [%s], remote tag [%s]" ,obj->is_server?"server":"client" ,obj ,obj->local_tag?obj->local_tag:"" ,obj->remote_tag?obj->remote_tag:""); set_state(obj,BELLE_SIP_DIALOG_NULL); return obj; }
/*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); }
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=belle_sip_response_get_return_hop(resp); base->channel=belle_sip_provider_get_channel(base->provider,hop); belle_sip_object_unref(hop); if (!base->channel){ belle_sip_error("Transaction [%p]: No channel available for sending response.",t); return; } belle_sip_object_ref(base->channel); belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t)); } 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); } /*12.1 Creation of a Dialog Dialogs are created through the generation of non-failure responses to requests with specific methods. Within this specification, only 2xx and 101-199 responses with a To tag, where the request was INVITE, will establish a dialog.*/ if (dialog && status_code>100 && status_code<300){ 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,BELLE_SIP_TRANSACTION(t),TRUE); }
static void process_request_event(void *ud, const belle_sip_request_event_t *event) { Sal *sal=(Sal*)ud; SalOp* op=NULL; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); belle_sip_header_address_t* origin_address; belle_sip_header_address_t* address=NULL; belle_sip_header_from_t* from_header; belle_sip_header_to_t* to; belle_sip_response_t* resp; belle_sip_header_t *evh; const char *method=belle_sip_request_get_method(req); belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); if (dialog) { op=(SalOp*)belle_sip_dialog_get_application_data(dialog); if (op == NULL && strcmp("NOTIFY",method) == 0) { /*special case for Dialog created by notify mathing subscribe*/ belle_sip_transaction_t * sub_trans = belle_sip_dialog_get_last_transaction(dialog); op = (SalOp*)belle_sip_transaction_get_application_data(sub_trans); } if (op==NULL || op->state==SalOpStateTerminated){ ms_warning("Receiving request for null or terminated op [%p], ignored",op); return; } }else{ /*handle the case where we are receiving a request with to tag but it is not belonging to any dialog*/ belle_sip_header_to_t *to = belle_sip_message_get_header_by_type(req, belle_sip_header_to_t); if ((strcmp("INVITE",method)==0 || strcmp("NOTIFY",method)==0) && (belle_sip_header_to_get_tag(to) != NULL)) { ms_warning("Receiving %s with to-tag but no know dialog here. Rejecting.", method); resp=belle_sip_response_create_from_request(req,481); belle_sip_provider_send_response(sal->prov,resp); return; /* by default (eg. when a to-tag is present), out of dialog ACK are automatically handled in lower layers (belle-sip) but in case it misses, it will be forwarded to us */ } else if (strcmp("ACK",method)==0 && (belle_sip_header_to_get_tag(to) == NULL)) { ms_warning("Receiving ACK without to-tag but no know dialog here. Ignoring"); return; } if (strcmp("INVITE",method)==0) { op=sal_op_new(sal); op->dir=SalOpDirIncoming; sal_op_call_fill_cbs(op); }else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { op=sal_op_new(sal); op->dir=SalOpDirIncoming; if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){ sal_op_presence_fill_cbs(op); }else sal_op_subscribe_fill_cbs(op); }else if (strcmp("MESSAGE",method)==0) { op=sal_op_new(sal); op->dir=SalOpDirIncoming; sal_op_message_fill_cbs(op); }else if (strcmp("OPTIONS",method)==0) { resp=belle_sip_response_create_from_request(req,200); belle_sip_provider_send_response(sal->prov,resp); return; }else if (strcmp("INFO",method)==0) { resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ belle_sip_provider_send_response(sal->prov,resp); return; }else if (strcmp("BYE",method)==0) { resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */ belle_sip_provider_send_response(sal->prov,resp); return; }else if (strcmp("CANCEL",method)==0) { resp=belle_sip_response_create_from_request(req,481);/*out of dialog CANCEL */ belle_sip_provider_send_response(sal->prov,resp); return; }else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) { resp=belle_sip_response_create_from_request(req,200);/*out of dialog PUBLISH */ belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA")); belle_sip_provider_send_response(sal->prov,resp); return; }else { ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req)); resp=belle_sip_response_create_from_request(req,405); belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp) ,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO"))); belle_sip_provider_send_response(sal->prov,resp); return; } } if (!op->base.from_address) { if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))) address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header)))) address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); else ms_error("Cannot not find from uri from request [%p]",req); sal_op_set_from_address(op,(SalAddress*)address); belle_sip_object_unref(address); } if( remote_contact ){ __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); } if (!op->base.to_address) { to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); if (belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))) address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))); else if ((belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to)))) address=belle_sip_header_address_create2(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) ,belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(to))); else ms_error("Cannot not find to uri from request [%p]",req); sal_op_set_to_address(op,(SalAddress*)address); belle_sip_object_unref(address); } if (!op->base.origin) { /*set origin uri*/ origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req)); __sal_op_set_network_origin_address(op,(SalAddress*)origin_address); belle_sip_object_unref(origin_address); } if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(req)); } if (!op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_call_id_t)))); } /*It is worth noting that proxies can (and will) remove this header field*/ sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req); sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); if (op->callbacks && op->callbacks->process_request_event) { op->callbacks->process_request_event(op,event); } else { ms_error("sal process_request_event not implemented yet"); } }