belle_sip_refresher_t* belle_sip_refresher_new(belle_sip_client_transaction_t* transaction) { belle_sip_refresher_t* refresher; belle_sip_transaction_state_t state=belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(transaction)); belle_sip_request_t* request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)); int is_register=strcmp("REGISTER",belle_sip_request_get_method(request))==0; refresher = (belle_sip_refresher_t*)belle_sip_object_new(belle_sip_refresher_t); refresher->transaction=transaction; refresher->state=stopped; refresher->number_of_retry=0; belle_sip_object_ref(transaction); refresher->retry_after=DEFAULT_RETRY_AFTER; if (belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(transaction))) { set_or_update_dialog(refresher, belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(transaction))); } belle_sip_provider_add_internal_sip_listener(transaction->base.provider,BELLE_SIP_LISTENER(refresher), is_register); if (set_expires_from_trans(refresher)==-1){ belle_sip_error("Unable to extract refresh value from transaction [%p]",transaction); } if (belle_sip_transaction_state_is_transient(state)) { belle_sip_message("Refresher [%p] takes ownership of transaction [%p]",refresher,transaction); transaction->base.is_internal=1; refresher->state=started; }else{ belle_sip_refresher_start(refresher); } return refresher; }
static void handle_notify(SalOp *op, belle_sip_request_t *req, belle_sip_dialog_t *dialog){ belle_sip_response_t* resp=NULL; belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); SalSubscribeStatus sub_state; if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { SalPresenceModel *presence_model = NULL; const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); if (op->dialog !=NULL && dialog != op->dialog){ ms_warning("Receiving a NOTIFY from a dialog we haven't stored (op->dialog=%p dialog=%p)", op->dialog, dialog); } if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { sub_state=SalSubscribeTerminated; ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); } else { sub_state=SalSubscribeActive; } presence_model = process_presence_notification(op, req); if (presence_model != NULL || body==NULL) { /* Presence notification body parsed successfully. */ resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */ op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); } else if (body){ /* Formatting error in presence notification body. */ ms_warning("Wrongly formatted presence document."); resp = sal_op_create_response_from_request(op, req, 488); } if (resp) belle_sip_server_transaction_send_response(server_transaction,resp); } }
static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_dialog_state_t dialog_state; 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 code = belle_sip_response_get_status_code(response); char reason[256]={0}; SalError error=SalErrorUnknown; SalReason sr=SalReasonUnknown; belle_sip_header_expires_t* expires; if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ return; } set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); if (!op->dialog) { ms_message("presence op [%p] receive out of dialog answer [%i]",op,code); return; } dialog_state=belle_sip_dialog_get_state(op->dialog); switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { ms_error("presence op [%p] receive an unexpected answer [%i]",op,code); break; } case BELLE_SIP_DIALOG_CONFIRMED: { if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) { expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); if(op->refresher) { belle_sip_refresher_stop(op->refresher); belle_sip_object_unref(op->refresher); op->refresher=NULL; } if (expires>0){ op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); } } break; } case BELLE_SIP_DIALOG_TERMINATED: if (op->refresher) { belle_sip_refresher_stop(op->refresher); belle_sip_object_unref(op->refresher); op->refresher=NULL; } break; default: { ms_error("presence op [%p] receive answer [%i] not implemented",op,code); } /* no break */ } }
static belle_sip_request_t *_belle_sip_dialog_create_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req, int queued){ belle_sip_request_t* req; const char *method=belle_sip_request_get_method(initial_req); belle_sip_header_content_length_t* content_lenth; belle_sip_list_t* headers; if (queued) req=belle_sip_dialog_create_queued_request(obj,method); else req=belle_sip_dialog_create_request(obj,method); if (req==NULL) return NULL; content_lenth = belle_sip_message_get_header_by_type(initial_req,belle_sip_header_content_length_t); /*first copy non system headers*/ headers = belle_sip_message_get_all_headers(BELLE_SIP_MESSAGE(initial_req)); belle_sip_list_for_each2(headers,(void (*)(void *, void *))copy_non_system_headers,req); belle_sip_list_free(headers); /*replicate via user parameters, if any, useful for 'alias' parameter in SUBSCRIBE requests*/ { belle_sip_header_via_t *orig_via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(initial_req),belle_sip_header_via_t); belle_sip_header_via_t *new_via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_via_t); belle_sip_parameters_copy_parameters_from(BELLE_SIP_PARAMETERS(new_via),BELLE_SIP_PARAMETERS(orig_via)); } /*copy body*/ if (content_lenth && belle_sip_header_content_length_get_content_length(content_lenth)>0) { belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),belle_sip_message_get_body(BELLE_SIP_MESSAGE(initial_req)),belle_sip_header_content_length_get_content_length(content_lenth)); } return req; }
static void handle_notify(SalOp *op, belle_sip_request_t *req){ belle_sip_response_t* resp; belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); SalSubscribeStatus sub_state; if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { SalPresenceModel *presence_model = NULL; const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); if (body==NULL){ ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); resp = sal_op_create_response_from_request(op, req, 415); belle_sip_server_transaction_send_response(server_transaction,resp); return; } presence_model = process_presence_notification(op, req); if (presence_model != NULL) { /* Presence notification body parsed successfully. */ if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { sub_state=SalSubscribeTerminated; ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); } else { sub_state=SalSubscribeActive; } resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */ op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); } else { /* Formatting error in presence notification body. */ ms_error("Wrongly formatted presence notification received"); resp = sal_op_create_response_from_request(op, req, 400); } belle_sip_server_transaction_send_response(server_transaction,resp); } }
void belle_sip_dialog_update_request(belle_sip_dialog_t *dialog, belle_sip_request_t *req){ belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_dialog_update_local_cseq(dialog,belle_sip_request_get_method(req)); if (dialog->route_set) belle_sip_message_add_headers((belle_sip_message_t*)req,dialog->route_set); belle_sip_request_set_uri(req,belle_sip_header_address_get_uri(dialog->remote_target)); belle_sip_header_cseq_set_seq_number(cseq,dialog->local_cseq); }
void belle_sip_transaction_set_state(belle_sip_transaction_t *t, belle_sip_transaction_state_t state) { belle_sip_message("Changing [%s] [%s] transaction [%p], from state [%s] to [%s]", BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ? "client" : "server", belle_sip_request_get_method(t->request), t, belle_sip_transaction_state_to_string(t->state), belle_sip_transaction_state_to_string(state)); t->state=state; }
int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { bool_t need_contact=FALSE; if (request==NULL) { return -1; /*sanity check*/ } /* Header field where proxy ACK BYE CAN INV OPT REG ___________________________________________________________ Contact R o - - m o o */ if (strcmp(belle_sip_request_get_method(request),"INVITE")==0 ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0 ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0 ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0 ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/ need_contact=TRUE; return _sal_op_send_request_with_contact(op, request,need_contact); }
static void caller_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { belle_sip_server_transaction_t* server_transaction; belle_sip_response_t* resp; belle_sip_dialog_t* dialog; belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t); if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) { belle_sip_message("Message [%p] not for caller, skipping",belle_sip_request_event_get_request(event)); return; /*not for the caller*/ } belle_sip_message("caller_process_request_event received [%s] message",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); server_transaction=belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event)); BC_ASSERT_STRING_EQUAL_FATAL("BYE",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(server_transaction)); BC_ASSERT_PTR_NOT_NULL_FATAL(dialog); BC_ASSERT_EQUAL(belle_sip_dialog_get_state(dialog) , BELLE_SIP_DIALOG_CONFIRMED, int, "%d"); resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); belle_sip_server_transaction_send_response(server_transaction,resp); }
static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_dialog_state_t dialog_state; belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); belle_sip_response_t* resp; const char *method=belle_sip_request_get_method(req); belle_sip_object_ref(server_transaction); if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=server_transaction; if (!op->dialog) { if (strcmp(method,"SUBSCRIBE")==0){ op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction)); belle_sip_dialog_set_application_data(op->dialog,op); sal_op_ref(op); ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); }else{ /* this is a NOTIFY */ ms_message("Receiving out of dialog notify"); handle_notify(op,req); return; } } dialog_state=belle_sip_dialog_get_state(op->dialog); switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); break; } case BELLE_SIP_DIALOG_EARLY: ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",method,op->dialog); break; case BELLE_SIP_DIALOG_CONFIRMED: if (strcmp("NOTIFY",method)==0) { handle_notify(op,req); } else if (strcmp("SUBSCRIBE",method)==0) { /*either a refresh or an unsubscribe*/ if (expires && belle_sip_header_expires_get_expires(expires)>0) { op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); } else if(expires) { ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); resp=sal_op_create_response_from_request(op,req,200); belle_sip_server_transaction_send_response(server_transaction,resp); } } break; default: ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); break; } }
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) { belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED); belle_sip_message("%s%s %s transaction [%p] terminated" ,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t)?"Client":"Server" ,t->is_internal?" internal":"" ,belle_sip_request_get_method(belle_sip_transaction_get_request(t)) ,t); BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); belle_sip_provider_set_transaction_terminated(t->provider,t); } }
int belle_sip_dialog_establish_full(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); if (strcmp(belle_sip_request_get_method(req),"INVITE")==0) obj->needs_ack=TRUE; if (obj->is_server && strcmp(belle_sip_request_get_method(req),"INVITE")==0){ belle_sip_dialog_init_200Ok_retrans(obj,resp); } else if (!obj->is_server && !obj->remote_target) { if (!ct) { belle_sip_error("Missing contact header in resp [%p] cannot set remote target for dialog [%p]",resp,obj); return -1; } obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); } /*update to tag*/ set_to_tag(obj,to); set_state(obj,BELLE_SIP_DIALOG_CONFIRMED); return 0; }
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); belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_uri_t *requri=belle_sip_request_get_uri(req); if (!to){ belle_sip_error("No to in response."); return -1; } if (!cseq){ belle_sip_error("No cseq in request."); return -1; } if (!via){ belle_sip_error("No via in request."); return -1; } if (strcasecmp(belle_sip_header_via_get_protocol(via),"TLS")==0 && belle_sip_uri_is_secure(requri)){ obj->is_secure=TRUE; } /**12.1.2 * The route set MUST be set to the list of URIs in the Record-Route *header field from the response, taken in reverse order and preserving *all URI parameters. If no Record-Route header field is present in *the response, the route set MUST be set to the empty set. **/ obj->route_set=belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref); for(elem=belle_sip_message_get_headers((belle_sip_message_t*)resp,BELLE_SIP_RECORD_ROUTE);elem!=NULL;elem=elem->next){ obj->route_set=belle_sip_list_prepend(obj->route_set,belle_sip_object_ref(belle_sip_header_route_create( (belle_sip_header_address_t*)elem->data))); } check_route_set(obj->route_set); /*contact might be provided later*/ if (ct) obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); obj->local_cseq=belle_sip_header_cseq_get_seq_number(cseq); /*call id is already set */ /*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; }
void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){ /*report the channel as possibly dead. If an alternate IP can be tryied, the channel will notify us with the RETRY state. * Otherwise it will report the error. * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded. **/ belle_sip_warning("Transaction [%p] reporting timeout, reporting to channel.",t); if (strcmp(belle_sip_request_get_method(t->request),"REGISTER")==0 && belle_sip_channel_notify_timeout(t->channel)==TRUE){ t->timed_out=TRUE; }else { notify_timeout(t); belle_sip_transaction_terminate(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_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); const char* method = belle_sip_request_get_method(req); 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 (status_code>=101 && status_code<300 && strcmp(method,"INVITE")==0 && (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_provider_find_dialog_from_message(t->base.provider,(belle_sip_message_t*)resp,FALSE); if (!dialog){ dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);/*belle_sip_dialog_new(base);*/ belle_sip_message("Handling response creating a new dialog !"); } } } } else if (should_dialog_be_created(t,resp)) { dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE); } if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) { /* retransmition, just return*/ belle_sip_message("[%p] is a 200 ok retransmition on dialog [%p], skiping",resp,dialog); return; } event.source=(belle_sip_object_t*)base->provider; event.client_transaction=t; event.dialog=dialog; event.response=(belle_sip_response_t*)resp; BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event); /*check that 200Ok for INVITEs have been acknowledged by listener*/ if (dialog && strcmp(method,"INVITE")==0){ belle_sip_dialog_check_ack_sent(dialog); } /*report a server having internal errors for REGISTER to the channel, in order to go to a fallback IP*/ if (status_code == 500 && strcmp(method,"REGISTER") == 0){ belle_sip_channel_notify_server_error(base->channel); } }
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) { int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t); belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED); if (t->dialog && (!t->last_response || belle_sip_response_get_status_code(t->last_response)<200)){ /*inform the dialog if a transaction terminates without final response.*/ belle_sip_dialog_update(t->dialog,t,!is_client); } belle_sip_message("%s%s %s transaction [%p] terminated" ,is_client ? "Client":"Server" ,t->is_internal ? " internal":"" ,belle_sip_request_get_method(belle_sip_transaction_get_request(t)) ,t); BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); belle_sip_provider_set_transaction_terminated(t->provider,t); } }
static void callee_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { belle_sip_dialog_t* dialog; belle_sip_response_t* ringing_response; belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t); const char* method; if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) { belle_sip_message("Message [%p] not for callee, skipping",belle_sip_request_event_get_request(event)); return; /*not for the callee*/ } method = belle_sip_request_get_method(belle_sip_request_event_get_request(event)); if (!server_transaction && strcmp(method,"ACK")!=0) { server_transaction= belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event)); } belle_sip_message("callee_process_request_event received [%s] message",method); dialog = belle_sip_request_event_get_dialog(event); if (!dialog ) { BC_ASSERT_STRING_EQUAL_FATAL("INVITE",method); dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(server_transaction)); callee_dialog=dialog; inserv_transaction=server_transaction; } if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) { ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),180); /*prepare 200ok*/ ok_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),200); content_length= belle_sip_header_content_length_create(strlen(sdp)); content_type = belle_sip_header_content_type_create("application","sdp"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_length)); belle_sip_message_set_body(BELLE_SIP_MESSAGE(ok_response),sdp,strlen(sdp)); belle_sip_object_ref(ok_response); /*only send ringing*/ belle_sip_server_transaction_send_response(server_transaction,ringing_response); } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) { /*time to send bye*/ belle_sip_client_transaction_t* client_transaction = belle_sip_provider_create_client_transaction(prov,belle_sip_dialog_create_request(dialog,"BYE")); belle_sip_client_transaction_send_request(client_transaction); } else { belle_sip_warning("Unexpected state [%s] for dialog [%p]",belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog)),dialog ); } }
static void testOptionMessage(void) { const char* raw_message = "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "From: <sip:[email protected]>;tag=465687829\r\n"\ "To: <sip:[email protected]>\r\n"\ "Call-ID: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "Contact: <sip:[email protected]:5062>\r\n"\ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Content-Length: 0\r\n\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); belle_sip_request_t* request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_request_get_uri(request)); belle_sip_object_unref(message); }
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_client_transaction_init(belle_sip_client_transaction_t *obj, 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")); char token[BELLE_SIP_BRANCH_ID_LENGTH]; if (!via){ belle_sip_fatal("belle_sip_client_transaction_init(): No via in request."); } if (strcmp(belle_sip_request_get_method(req),"CANCEL")!=0){ obj->base.branch_id=belle_sip_strdup_printf(BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",belle_sip_random_token(token,sizeof(token))); belle_sip_header_via_set_branch(via,obj->base.branch_id); }else{ obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via)); } belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req); }
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { SalOp* op = (SalOp*)user_ctx; belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event); belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); belle_sip_request_t* req; belle_sip_response_t* resp; if (client_transaction) { req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); } else { req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); } if (op->state ==SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(req))==0 && (!resp || (belle_sip_response_get_status_code(resp) !=401 && belle_sip_response_get_status_code(resp) !=407))) { if (op->dialog==NULL) call_set_released(op); } }
void channel_parser_tester_recovery_from_error_base (const char* prelude,const char* raw_message) { belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , 45421 , NULL , "127.0.0.1" , 45421); belle_sip_request_t* request; belle_sip_message_t* message; if (prelude) { channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,prelude); channel->input_stream.write_ptr+=strlen(prelude); belle_sip_channel_parse_stream(channel,FALSE); } channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,FALSE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_sip_request_t)); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Expires")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_EXPIRES(belle_sip_message_get_header(message,"Expires"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Proxy-Authorization")); check_uri_and_headers(message); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(stack); }
int belle_sip_dialog_is_authorized_transaction(const belle_sip_dialog_t *dialog,const char* method) { if (belle_sip_dialog_request_pending(dialog)){ const char* last_transaction_request; if (strcasecmp(method,"BYE")==0) return TRUE; /*don't reject a BYE*/ last_transaction_request = belle_sip_request_get_method(belle_sip_transaction_get_request(dialog->last_transaction)); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(dialog->last_transaction,belle_sip_client_transaction_t) && strcmp(last_transaction_request,"SUBSCRIBE")==0 && strcmp(method,"NOTIFY")==0){ /*stupid as it is, you have to accept a NOTIFY for a SUBSCRIBE for which no answer is received yet...*/ return TRUE; } if (strcmp(last_transaction_request,"INVITE")==0 && (strcmp(method,"PRACK")==0 || strcmp(method,"UPDATE")==0)){ /*PRACK /UPDATE needs to be sent or received during reINVITEs.*/ return TRUE; } return FALSE; } else { return TRUE; } }
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; 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)==0) server_transaction_notify(t,req,dialog); /*else nothing to do because retransmission of ACK*/ } }else{ belle_sip_warning("ACK received for non-invite server transaction ?"); } }else if (strcmp(method,"CANCEL")==0){ server_transaction_notify(t,req,t->base.dialog); }else BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t); }
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){ belle_sip_message_t *orig=(belle_sip_message_t*)t->base.request; belle_sip_request_t *req; const char *orig_method=belle_sip_request_get_method((belle_sip_request_t*)orig); if (strcmp(orig_method,"ACK")==0 || strcmp(orig_method,"INVITE")!=0){ 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){ 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"); /* 9.1 Client Behavior Since requests other than INVITE are responded to immediately, sending a CANCEL for a non-INVITE request would always create a race condition. The following procedures are used to construct a CANCEL request. The Request-URI, Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request MUST be identical to those in the request being cancelled, including tags. A CANCEL constructed by a client MUST have only a single Via header field value matching the top Via value in the request being cancelled.*/ belle_sip_request_set_uri(req,(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri((belle_sip_request_t*)orig))); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"via",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"call-id",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"from",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"to",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"route",TRUE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE); belle_sip_message_add_header((belle_sip_message_t*)req, (belle_sip_header_t*)belle_sip_header_cseq_create( belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header(orig,"cseq")), "CANCEL")); return req; }
static void server_process_request_event(void *obj, const belle_sip_request_event_t *event){ endpoint_t* endpoint = (endpoint_t*)obj; belle_sip_server_transaction_t* server_transaction =belle_sip_provider_create_server_transaction(endpoint->provider,belle_sip_request_event_get_request(event)); belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); belle_sip_response_t* resp; belle_sip_header_contact_t* contact; belle_sip_header_expires_t* expires; belle_sip_header_authorization_t* authorization; belle_sip_header_via_t* via; const char* raw_authenticate_digest = "WWW-Authenticate: Digest " "algorithm=MD5, realm=\"" SIPDOMAIN "\", opaque=\"1bc7f9097684320\""; belle_sip_header_www_authenticate_t* www_authenticate=NULL; const char* auth_uri; const char* qop; unsigned char auth_ok=0; char local_resp[33]; belle_sip_message("caller_process_request_event received [%s] message",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); switch (endpoint->auth) { case none: { auth_ok=1; break; } case digest_auth: case digest: { if ((authorization=belle_sip_message_get_header_by_type(req,belle_sip_header_authorization_t)) != NULL){ qop=belle_sip_header_authorization_get_qop(authorization); if (qop && strcmp(qop,"auth")==0) { compute_response_auth_qop( belle_sip_header_authorization_get_username(authorization) ,belle_sip_header_authorization_get_realm(authorization) ,PASSWD ,endpoint->nonce ,endpoint->nonce_count ,belle_sip_header_authorization_get_cnonce(authorization) ,belle_sip_header_authorization_get_qop(authorization) ,belle_sip_request_get_method(req) ,auth_uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization)) ,local_resp); } else { /*digest*/ compute_response(belle_sip_header_authorization_get_username(authorization) ,belle_sip_header_authorization_get_realm(authorization) ,PASSWD ,endpoint->nonce ,belle_sip_request_get_method(req) ,auth_uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization)) ,local_resp); } belle_sip_free((void*)auth_uri); auth_ok=strcmp(belle_sip_header_authorization_get_response(authorization),local_resp)==0; } if (auth_ok && endpoint->nonce_count<MAX_NC_COUNT ) {/*revoke nonce after MAX_NC_COUNT uses*/ if (endpoint->auth == digest ) { sprintf(endpoint->nonce,"%p",authorization); //*change the nonce for next auth*/ } else { endpoint->nonce_count++; } } else { auth_ok=0; www_authenticate=belle_sip_header_www_authenticate_parse(raw_authenticate_digest); sprintf(endpoint->nonce,"%p",authorization); //*change the nonce for next auth*/ belle_sip_header_www_authenticate_set_nonce(www_authenticate,endpoint->nonce); if (endpoint->auth == digest_auth) { belle_sip_header_www_authenticate_add_qop(www_authenticate,"auth"); if (endpoint->nonce_count>=MAX_NC_COUNT) { belle_sip_header_www_authenticate_set_stale(www_authenticate,1); endpoint->nonce_count=1; } } } } break; default: break; } if (auth_ok) { resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); if (!endpoint->expire_in_contact) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires=belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t))); } if (strcmp(belle_sip_request_get_method(req),"REGISTER")==0) { contact=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); } else { contact=belle_sip_header_contact_new(); } if(endpoint->unreconizable_contact) { /*put an unexpected address*/ belle_sip_uri_set_host(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact)),"nimportequoi.com"); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(contact)); if (strcmp(belle_sip_request_get_method(req),"PUBLISH")==0) { belle_sip_header_t* sip_if_match=belle_sip_message_get_header(BELLE_SIP_MESSAGE(resp),"SIP-If-Match"); if (sip_if_match) { CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(sip_if_match)),"blablietag"); } /*check for body*/ CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))); if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) { CU_ASSERT_STRING_EQUAL(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),publish_body); } CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header_by_type(req,belle_sip_header_content_length_t)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),belle_sip_header_create("SIP-ETag","blablietag")); } } else { resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),401); if (www_authenticate) belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(www_authenticate)); } if (endpoint->received) { via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_header_via_set_received(via,endpoint->received); } belle_sip_server_transaction_send_response(server_transaction,resp); }
BELLESIP_EXPORT const char *belle_sip_transaction_get_method(const belle_sip_transaction_t *t){ return belle_sip_request_get_method(t->request); }
static unsigned int should_dialog_be_created(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){ belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); const char* method = belle_sip_request_get_method(req); int status_code = belle_sip_response_get_status_code(resp); return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0); }
static void process_request_event(void *sal, const belle_sip_request_event_t *event) { 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; 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); 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 || op->state==SalOpStateTerminated){ ms_warning("Receiving request for null or terminated op [%p], ignored",op); return; } }else if (strcmp("INVITE",method)==0) { op=sal_op_new((Sal*)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*)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*)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*)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*)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*)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,501); belle_sip_provider_send_response(((Sal*)sal)->prov,resp); return; } if (!op->base.from_address) { 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))); sal_op_set_from_address(op,(SalAddress*)address); belle_sip_object_unref(address); } if (!op->base.to_address) { to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); 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))); 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.process_request_event) { op->callbacks.process_request_event(op,event); } else { ms_error("sal process_request_event not implemented yet"); } }
static void process_response_event(void *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); int response_code = belle_sip_response_get_status_code(response); if (!client_transaction) { ms_warning("Discarding stateless response [%i]",response_code); return; } else { SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_header_contact_t* original_contact; belle_sip_header_address_t* contact_address=NULL; belle_sip_header_via_t* via_header; belle_sip_uri_t* contact_uri; unsigned int contact_port; const char* received; int rport; bool_t contact_updated=FALSE; char* new_contact; if (op->state == SalOpStateTerminated) { belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); return; } if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); } 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(response), belle_sip_header_call_id_t)))); } sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); if (op->callbacks.process_response_event) { if (op->base.root->nat_helper_enabled) { /*Fix contact if needed*/ via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); received = belle_sip_header_via_get_received(via_header); rport = belle_sip_header_via_get_rport(via_header); if ((original_contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t))) { /*update contact with sent values in any cases*/ contact_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(original_contact))); sal_op_set_contact_address(op,(const SalAddress *)contact_address); belle_sip_object_unref(contact_address); } if (sal_op_get_contact(op)){ if (received!=NULL || rport>0) { contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op))); contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address)); if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) { /*need to update host*/ belle_sip_uri_set_host(contact_uri,received); contact_updated=TRUE; } contact_port = belle_sip_uri_get_port(contact_uri); if (rport>0 && rport!=contact_port && (contact_port+rport)!=5060) { /*need to update port*/ belle_sip_uri_set_port(contact_uri,rport); contact_updated=TRUE; } /*try to fix transport if needed (very unlikely)*/ if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { if (!belle_sip_uri_get_transport_param(contact_uri) ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); contact_updated=TRUE; } } else { if (belle_sip_uri_get_transport_param(contact_uri)) { contact_updated=TRUE; belle_sip_uri_set_transport_param(contact_uri,NULL); } } if (contact_updated) { char* old_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(sal_op_get_contact_address(op))); new_contact=belle_sip_object_to_string(BELLE_SIP_OBJECT(contact_address)); ms_message("Updating contact from [%s] to [%s] for [%p]",old_contact,new_contact,op); sal_op_set_contact_address(op,(const SalAddress *)contact_address); belle_sip_free(new_contact); belle_sip_free(old_contact); } if (contact_address)belle_sip_object_unref(contact_address); } } } /*handle authorization*/ switch (response_code) { case 200: { break; } case 401: case 407:{ /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ belle_sip_message("Op is in state terminating, nothing else to do "); } else { if (op->pending_auth_transaction){ belle_sip_object_unref(op->pending_auth_transaction); op->pending_auth_transaction=NULL; } op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); sal_process_authentication(op); return; } } } op->callbacks.process_response_event(op,event); } else { ms_error("Unhandled event response [%p]",event); } } }
static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_uri_t* outbound_proxy=NULL; belle_sip_header_contact_t* contact; int result =-1; belle_sip_uri_t *next_hop_uri=NULL; if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) { contact = sal_op_create_contact(op); belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); } /*keep existing*/ _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { /*don't put route header if dialog is in confirmed state*/ const MSList *elem=sal_op_get_route_addresses(op); const char *transport; const char *method=belle_sip_request_get_method(request); belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP"); if (elem) { outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); next_hop_uri=outbound_proxy; }else{ next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); } transport=belle_sip_uri_get_transport_param(next_hop_uri); if (transport==NULL){ /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use * the first available transport*/ if (!belle_sip_uri_is_secure(next_hop_uri)){ if (udplp==NULL){ if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ transport="tcp"; }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ transport="tls"; } } if (transport){ belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); belle_sip_uri_set_transport_param(next_hop_uri,transport); } } }else{ #ifdef TUNNEL_ENABLED if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){ /* our tunnel mode only supports UDP. Force transport to be set to UDP */ belle_sip_uri_set_transport_param(next_hop_uri,"udp"); } #endif } if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); } } client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_object_ref(op->pending_client_trans); if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm); } result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); /*update call id if not set yet for this OP*/ if (result == 0 && !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(request), belle_sip_header_call_id_t)))); } return result; }