static void cancelling_invite(SalOp* op ){ belle_sip_request_t* cancel; ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans); sal_op_send_request(op,cancel); op->state=SalOpStateTerminating; }
void sal_call_send_vfu_request(SalOp *op){ char info_body[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" "<media_control>" " <vc_primitive>" " <to_encoder>" " <picture_fast_update></picture_fast_update>" " </to_encoder>" " </vc_primitive>" "</media_control>"; size_t content_lenth = sizeof(info_body) - 1; belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/ if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) { belle_sip_request_t* info = belle_sip_dialog_create_queued_request(op->dialog,"INFO"); int error=TRUE; if (info) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml"))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth); error=sal_op_send_request(op,info); } if (error) ms_warning("Cannot send vfu request to [%s] ", sal_op_get_to(op)); } else { ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",sal_op_get_to(op) ,op->dialog ,belle_sip_dialog_state_to_string(dialog_state)); } return ; }
void sal_process_authentication(SalOp *op) { belle_sip_request_t* request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); bool_t is_within_dialog=FALSE; belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); sal_add_pending_auth(op->base.root,op); if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)request); is_within_dialog=TRUE; } else { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); } if (belle_sip_provider_add_authorization(op->base.root->prov,request,response,&auth_list)) { if (is_within_dialog) { sal_op_send_request(op,request); } else { sal_op_resend_request(op,request); } sal_remove_pending_auth(op->base.root,op); }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); if (is_within_dialog) { belle_sip_object_unref(request); } if (op->auth_info) sal_auth_info_delete(op->auth_info); auth_event=(belle_sip_auth_event_t*)(auth_list->data); op->auth_info=sal_auth_info_create(auth_event); belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); } }
/*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires){ belle_sip_request_t *req=NULL; if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); sal_op_presence_fill_cbs(op); if (expires==-1){ if (op->refresher){ expires=belle_sip_refresher_get_expires(op->refresher); belle_sip_object_unref(op->refresher); op->refresher=NULL; }else{ ms_error("sal_subscribe_presence(): cannot guess expires from previous refresher."); return -1; } } if (!op->event){ op->event=belle_sip_header_create("Event","presence"); belle_sip_object_ref(op->event); } belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag"); belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag"); req=sal_op_build_request(op,"SUBSCRIBE"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); return sal_op_send_request(op,req); }
int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* invite; op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); ms_message("[%s] calling [%s] on op [%p]", from, to, op); invite=sal_op_build_request(op,"INVITE"); if( invite == NULL ){ /* can happen if the op has an invalid address */ return -1; } sal_op_fill_invite(op,invite); sal_op_call_fill_cbs(op); if (op->replaces){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces)); } if (op->referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by)); return sal_op_send_request(op,invite); }
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime=time(NULL); if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ req=belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); }else{ sal_op_message_fill_cbs(op); if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); op->dir=SalOpDirOutgoing; req=sal_op_build_request(op,"MESSAGE"); if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } } snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); return sal_op_send_request(op,req); }
void sal_process_authentication(SalOp *op) { belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); belle_sip_request_t* new_request; bool_t is_within_dialog=FALSE; belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t); belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){ /*prefer using the from from the SalOp*/ from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op)); } if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); if (!new_request) new_request = belle_sip_dialog_create_queued_request_from(op->dialog,initial_request); is_within_dialog=TRUE; } else { new_request=initial_request; belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION); } if (new_request==NULL) { ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op); return; } if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list,op->base.realm)) { if (is_within_dialog) { sal_op_send_request(op,new_request); } else { sal_op_resend_request(op,new_request); } sal_remove_pending_auth(op->base.root,op); }else { belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t); char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); ms_message("No auth info found for [%s]",tmp); belle_sip_free(tmp); sal_add_pending_auth(op->base.root,op); if (is_within_dialog) { belle_sip_object_unref(new_request); } } /*always store auth info, for case of wrong credential*/ if (op->auth_info) { sal_auth_info_delete(op->auth_info); op->auth_info=NULL; } if (auth_list){ auth_event=(belle_sip_auth_event_t*)(auth_list->data); op->auth_info=sal_auth_info_create(auth_event); belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); } }
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ if (op->dialog){ belle_sip_request_t *req=belle_sip_dialog_create_request(op->dialog,"INFO"); sal_op_add_body(op,(belle_sip_message_t*)req,body); return sal_op_send_request(op,req); } return -1; }
int sal_call_update(SalOp *op, const char *subject){ belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); if (reinvite){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); sal_op_fill_invite(op, reinvite); return sal_op_send_request(op,reinvite); } return -1; }
int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); if (!expires_header && expires>=0) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); } if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); return sal_op_send_request(op,request); }
int sal_notify_close(SalOp *op){ belle_sip_request_t* notify; if (!op->dialog) return -1; if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); return sal_op_send_request(op,notify); }
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body_handler){ if (op->dialog){ belle_sip_request_t *req; belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); req=belle_sip_dialog_create_queued_request(op->dialog,"INFO"); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler)); return sal_op_send_request(op,req); } return -1; }
int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){ char* tmp; belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):sal_op_build_request(op, "REFER"); if (!req) { tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to))); ms_error("Cannot refer to [%s] for op [%p]",tmp,op); belle_sip_free(tmp); return -1; } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to)); if (referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(referred_by)); return sal_op_send_request(op,req); }
int sal_notify_presence_close(SalOp *op){ belle_sip_request_t* notify=NULL; if (sal_op_check_dialog_state(op)) { return -1; } notify=create_presence_notify(op); if (!notify) return-1; sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); return sal_op_send_request(op,notify); }
static int send_notify_for_refer(SalOp* op, int code, const char *reason){ belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"); char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason); size_t content_length=strlen(sipfrag); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag"))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); return sal_op_send_request(op,notify); }
int sal_notify(SalOp *op, const SalBody *body){ belle_sip_request_t* notify; if (!op->dialog) return -1; if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event); belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600))); sal_op_add_body(op,(belle_sip_message_t*)notify, body); return sal_op_send_request(op,notify); }
void sal_process_authentication(SalOp *op) { belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); belle_sip_request_t* new_request; bool_t is_within_dialog=FALSE; belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); if (!new_request) new_request = belle_sip_dialog_create_queued_request_from(op->dialog,initial_request); is_within_dialog=TRUE; } else { new_request=initial_request; belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION); } if (new_request==NULL) { ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op); return; } if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) { if (is_within_dialog) { sal_op_send_request(op,new_request); } else { sal_op_resend_request(op,new_request); } sal_remove_pending_auth(op->base.root,op); }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); sal_add_pending_auth(op->base.root,op); if (is_within_dialog) { belle_sip_object_unref(new_request); } } /*always store auth info, for case of wrong credential*/ if (op->auth_info) sal_auth_info_delete(op->auth_info); if (auth_list){ auth_event=(belle_sip_auth_event_t*)(auth_list->data); op->auth_info=sal_auth_info_create(auth_event); belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); } }
int sal_call_send_dtmf(SalOp *h, char dtmf){ if (h->dialog && (belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_CONFIRMED || belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_EARLY)){ belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO"); if (req){ int bodylen; char dtmf_body[128]={0}; snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf); bodylen=strlen(dtmf_body); belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen); belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create(bodylen)); belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_type_create("application", "dtmf-relay")); sal_op_send_request(h,req); }else ms_error("sal_call_send_dtmf(): could not build request"); }else ms_error("sal_call_send_dtmf(): no dialog"); return 0; }
int sal_call_terminate(SalOp *op){ belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) { ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state)); return -1; } switch(dialog_state) { case BELLE_SIP_DIALOG_CONFIRMED: { sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); op->state=SalOpStateTerminating; break; } case BELLE_SIP_DIALOG_NULL: { if (op->dir == SalOpDirIncoming) { sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; } else if (op->pending_client_trans){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ cancelling_invite(op); }else{ /* Case where the CANCEL cannot be sent because no provisional response was received so far. * The Op must be kept for the time of the transaction in case a response is received later. * The state is passed to Terminating to remember to terminate later. */ op->state=SalOpStateTerminating; } } break; } case BELLE_SIP_DIALOG_EARLY: { if (op->dir == SalOpDirIncoming) { sal_call_decline(op, SalReasonDeclined,NULL); op->state=SalOpStateTerminated; } else { cancelling_invite(op); } break; } default: { ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); return -1; } } return 0; }
int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ belle_sip_request_t *update; belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog); /*check for dialog state*/ if ( state == BELLE_SIP_DIALOG_CONFIRMED) { if (no_user_consent) update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); else update=belle_sip_dialog_create_request(op->dialog,"INVITE"); } else if (state == BELLE_SIP_DIALOG_EARLY) { update=belle_sip_dialog_create_request(op->dialog,"UPDATE"); } else { ms_error("Cannot update op [%p] with dialog [%p] in state [%s]",op, op->dialog,belle_sip_dialog_state_to_string(state)); return -1; } if (update){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject)); sal_op_fill_invite(op, update); return sal_op_send_request(op,update); } return -1; }
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; belle_sip_dialog_state_t dialog_state; belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_request_t* req; belle_sip_response_t* response=belle_sip_response_event_get_response(event); int code = belle_sip_response_get_status_code(response); belle_sip_header_content_type_t *header_content_type=NULL; belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event); const char *method; if (!client_transaction) { ms_warning("Discarding stateless response [%i] on op [%p]",code,op); return; } req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); set_or_update_dialog(op,dialog); dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; method=belle_sip_request_get_method(req); ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state)); /*to make sure no cb will destroy op*/ sal_op_ref(op); switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { if (strcmp("INVITE",method)==0 ) { if (op->state == SalOpStateTerminating) { /*check if CANCEL was sent before*/ if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { /*it wasn't sent */ if (code<200) { cancelling_invite(op); }else{ /* no need to send the INVITE because the UAS rejected the INVITE*/ if (op->dialog==NULL) call_set_released(op); } } else { /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ if (code>=300){ if (op->dialog==NULL) call_set_released(op); } } } else if (code >= 180 && code<200) { belle_sip_response_t *prev_response=belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response"); if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ handle_sdp_from_response(op,response); op->base.root->callbacks.call_ringing(op); } belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); } else if (code>=300){ call_set_error(op,response); if (op->dialog==NULL) call_set_released(op); } } else if (code >=200 && code<300 && strcmp("UPDATE",belle_sip_request_get_method(req))==0) { handle_sdp_from_response(op,response); op->base.root->callbacks.call_accepted(op); } } break; case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { case SalOpStateEarly:/*invite case*/ case SalOpStateActive: /*re-invite, INFO, UPDATE case*/ if (strcmp("INVITE",method)==0){ if (code >=200 && code<300) { handle_sdp_from_response(op,response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack==NULL) { ms_error("This call has been already terminated."); return ; } if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); belle_sip_object_unref(op->sdp_answer); op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); op->base.root->callbacks.call_accepted(op); /*INVITE*/ op->state=SalOpStateActive; }else if (code >= 300){ call_set_error(op,response); } }else if (strcmp("INFO",method)==0){ if (code == 491 && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { unsigned int retry_in =1000*((float)rand()/RAND_MAX); belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry"); ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); belle_sip_object_unref(s); }else { /*ignoring*/ } }else if (strcmp("UPDATE",method)==0){ op->base.root->callbacks.call_accepted(op); /*INVITE*/ } break; case SalOpStateTerminating: sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); break; case SalOpStateTerminated: default: ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, sal_op_state_to_string(op->state)); } } break; case BELLE_SIP_DIALOG_TERMINATED: { if (code >= 300){ call_set_error(op,response); } } break; default: { ms_error("call op [%p] receive answer [%i] not implemented",op,code); } break; } sal_op_unref(op); }
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,request); }
/*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to){ sal_op_set_from(op,from); sal_op_set_to(op,to); return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS")); }
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; belle_sip_dialog_state_t dialog_state; belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_request_t* req; belle_sip_response_t* response=belle_sip_response_event_get_response(event); int code = belle_sip_response_get_status_code(response); if (!client_transaction) { ms_warning("Discarding stateless response [%i] on op [%p]",code,op); return; } req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state)); switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: case BELLE_SIP_DIALOG_EARLY: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { if (op->state == SalOpStateTerminating) { /*check if CANCEL was sent before*/ if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { /*it wasn't sent */ if (code<200) { cancelling_invite(op); }else{ /* no need to send the INVITE because the UAS rejected the INVITE*/ if (op->dialog==NULL) call_set_released(op); } } else { /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ if (code>=300){ if (op->dialog==NULL) call_set_released(op); } } } else if (code >= 180 && code<300) { handle_sdp_from_response(op,response); op->base.root->callbacks.call_ringing(op); } else if (code>=300){ call_set_error(op,response); if (op->dialog==NULL) call_set_released(op); } } } break; case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { case SalOpStateEarly:/*invite case*/ case SalOpStateActive: /*re-invite case*/ if (code >=200 && code<300 && strcmp("INVITE",belle_sip_request_get_method(req))==0) { handle_sdp_from_response(op,response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack==NULL) { ms_error("This call has been already terminated."); return ; } if (op->sdp_answer){ set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); belle_sip_object_unref(op->sdp_answer); op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); op->base.root->callbacks.call_accepted(op); /*INVITE*/ op->state=SalOpStateActive; } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ call_set_error(op,response); } else { /*ignoring*/ } break; case SalOpStateTerminating: sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); break; case SalOpStateTerminated: default: ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, sal_op_state_to_string(op->state)); } } break; case BELLE_SIP_DIALOG_TERMINATED: { if (code >= 300){ call_set_error(op,response); } } break; default: { ms_error("call op [%p] receive answer [%i] not implemented",op,code); } break; } }
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){ belle_sip_request_t* req; char content_type_raw[256]; size_t content_length = msg?strlen(msg):0; time_t curtime = time(NULL); uint8_t *multipartEncryptedMessage = NULL; int retval; if (op->dialog){ /*for SIP MESSAGE that are sent in call's dialog*/ req = belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE"); }else{ sal_op_message_fill_cbs(op); if (from) sal_op_set_from(op, from); if (to) sal_op_set_to(op, to); op->dir = SalOpDirOutgoing; req = sal_op_build_request(op,"MESSAGE"); if (req == NULL ){ return -1; } if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(sal_op_create_contact(op))); } } /* shall we try to encrypt the message?*/ if ((strcmp(content_type, "xml/cipher") == 0) || ((strcmp(content_type, "application/cipher.vnd.gsma.rcs-ft-http+xml") == 0))) { /* access the zrtp cache to get keys needed to cipher the message */ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); FILE *CACHEFD = fopen(lc->zrtp_secrets_cache, "rb+"); if (CACHEFD == NULL) { ms_warning("Unable to access ZRTP ZID cache to encrypt message"); /*probably not a good idea to do this:*/ sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return -1; } else { size_t cacheSize; char *cacheString; xmlDocPtr cacheXml; int retval; cacheString=ms_load_file_content(CACHEFD, &cacheSize); if (!cacheString){ ms_warning("Unable to load content of ZRTP ZID cache to encrypt message"); return -1; } cacheString[cacheSize] = '\0'; cacheSize += 1; fclose(CACHEFD); cacheXml = xmlParseDoc((xmlChar*)cacheString); ms_free(cacheString); retval = lime_createMultipartMessage(cacheXml, (uint8_t *)msg, (uint8_t *)peer_uri, &multipartEncryptedMessage); if (retval != 0) { ms_warning("Unable to encrypt message for %s : %s - op [%p]", peer_uri, lime_error_code_to_string(retval), op); xmlFreeDoc(cacheXml); free(multipartEncryptedMessage); /*probably not a good idea to do this:*/ sal_error_info_set(&op->error_info, SalReasonNotAcceptable, 488, "Unable to encrypt IM", NULL); op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); return -1; } else { /* dump updated cache to a string */ xmlChar *xmlStringOutput; int xmlStringLength; xmlDocDumpFormatMemoryEnc(cacheXml, &xmlStringOutput, &xmlStringLength, "UTF-8", 0); /* write it to the cache file */ CACHEFD = fopen(lc->zrtp_secrets_cache, "wb+"); if (fwrite(xmlStringOutput, 1, xmlStringLength, CACHEFD)<=0){ ms_warning("Unable to write zid cache"); } xmlFree(xmlStringOutput); fclose(CACHEFD); content_length = strlen((const char *)multipartEncryptedMessage); } xmlFreeDoc(cacheXml); } } snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),(multipartEncryptedMessage==NULL)?msg:(const char *)multipartEncryptedMessage,content_length); retval = sal_op_send_request(op,req); free(multipartEncryptedMessage); return retval; }