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; bool_t release_call=FALSE; 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)) && op->dialog==NULL) { release_call=TRUE; } if (server_transaction){ if (op->pending_server_trans==server_transaction){ belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=NULL; } if (op->pending_update_server_trans==server_transaction){ belle_sip_object_unref(op->pending_update_server_trans); op->pending_update_server_trans=NULL; } } if (release_call) call_set_released(op); }
static void caller_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_header_from_t* from=belle_sip_message_get_header_by_type(belle_sip_response_event_get_response(event),belle_sip_header_from_t); belle_sip_header_cseq_t* invite_cseq=belle_sip_message_get_header_by_type(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)),belle_sip_header_cseq_t); belle_sip_request_t* ack; belle_sip_dialog_t* dialog; int status; if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)))) { belle_sip_message("Message [%p] not for caller, skipping",belle_sip_response_event_get_response(event)); return; /*not for the caller*/ } status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); belle_sip_message("caller_process_response_event [%i]",status); if (BC_ASSERT_PTR_NOT_NULL(client_transaction)) { dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(client_transaction)); if (BC_ASSERT_PTR_NOT_NULL(dialog)) { BC_ASSERT_PTR_EQUAL(caller_dialog,dialog); if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) { BC_ASSERT_EQUAL(status,100, int, "%d"); } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_EARLY){ BC_ASSERT_EQUAL(status,180, int, "%d"); /*send 200ok from callee*/ belle_sip_server_transaction_send_response(inserv_transaction,ok_response); belle_sip_object_unref(ok_response); ok_response=NULL; } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) {
int sal_call_notify_ringing(SalOp *op, bool_t early_media){ int status_code =early_media?183:180; belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code); belle_sip_header_t *require; const char *tags=NULL; if (early_media){ handle_offer_answer_response(op,ringing_response); } require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require"); if (require) tags=belle_sip_header_get_unparsed_value(require); /* if client requires 100rel, then add necessary stuff*/ if (tags && strstr(tags,"100rel")!=0) { belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel")); belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); } #ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING if (tags && strstr(tags,"100rel")!=0) #endif { belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); belle_sip_header_contact_t* contact_header; if (contact && (contact_header=belle_sip_header_contact_create(contact))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); } } belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); return 0; }
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); sal_op_publish_fill_cbs(op); req=sal_op_build_request(op,"PUBLISH"); if (sal_op_get_contact(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); } else { /*update status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); /*update body*/ sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL); return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires); } }
int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ belle_sip_response_t* response; belle_sip_header_contact_t* contact=NULL; int status=sal_reason_to_sip_code(reason); belle_sip_transaction_t *trans; if (reason==SalReasonRedirect){ if (redirection!=NULL) { if (strstr(redirection,"sip:")!=0) status=302; else status=380; contact= belle_sip_header_contact_new(); belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); } else { ms_error("Cannot redirect to null"); } } trans=(belle_sip_transaction_t*)op->pending_server_trans; if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; if (!trans){ ms_error("sal_call_decline(): no pending transaction to decline."); return -1; } response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); return 0; }
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); } }
/*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h){ belle_sip_response_t *response; belle_sip_header_contact_t* contact_header; if (!h->pending_server_trans) { ms_error("No transaction to accept for op [%p]",h); return -1; } /* sends a 200 OK */ response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200); if (response==NULL){ ms_error("Fail to build answer for call"); return -1; } belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow())); if (h->base.root->session_expires!=0){ if (h->supports_session_timers) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer")); } } if ((contact_header=sal_op_create_contact(h))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); } handle_offer_answer_response(h,response); belle_sip_server_transaction_send_response(h->pending_server_trans,response); return 0; }
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 */ } }
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){ belle_sip_request_t *req=NULL; if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); if (!op->dialog){ sal_op_subscribe_fill_cbs(op); /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ req=sal_op_build_request(op,"SUBSCRIBE"); if (eventname){ if (op->event) belle_sip_object_unref(op->event); op->event=belle_sip_header_create("Event",eventname); belle_sip_object_ref(op->event); } 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))); sal_op_add_body(op,(belle_sip_message_t*)req,body); return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener); }else if (op->refresher){ const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); /* modify last request to update body*/ sal_op_add_body(op,(belle_sip_message_t*)last_req,body); return belle_sip_refresher_refresh(op->refresher,expires); } ms_warning("sal_subscribe(): no dialog and no refresher ?"); return -1; }
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 int set_expires_from_trans(belle_sip_refresher_t* refresher) { belle_sip_transaction_t* transaction = BELLE_SIP_TRANSACTION(refresher->transaction); belle_sip_response_t*response=transaction->last_response; belle_sip_request_t*request=belle_sip_transaction_get_request(transaction); belle_sip_header_expires_t* expires_header=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); belle_sip_header_contact_t* contact_header; refresher->obtained_expires=-1; if (strcmp("REGISTER",belle_sip_request_get_method(request))==0 || expires_header /*if request has an expire header, refresher can always work*/) { if (expires_header) refresher->target_expires = belle_sip_header_expires_get_expires(expires_header); /*An "expires" parameter on the "Contact" header has no semantics for * SUBSCRIBE and is explicitly not equivalent to an "Expires" header in * a SUBSCRIBE request or response. */ if (strcmp("REGISTER",belle_sip_request_get_method(request))==0){ if (!expires_header && (contact_header=belle_sip_message_get_header_by_type((belle_sip_message_t*)request,belle_sip_header_contact_t))){ int ct_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); if (ct_expires!=-1) refresher->target_expires=ct_expires; } /*check in response also to get the obtained expires*/ if ((contact_header=belle_sip_refresher_get_contact(refresher))!=NULL){ /*matching contact, check for its possible expires param*/ refresher->obtained_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); } } if (refresher->obtained_expires==-1){ /*no contact with expire or not relevant, looking for Expires header*/ if (response && (expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { refresher->obtained_expires = belle_sip_header_expires_get_expires(expires_header); } } if (refresher->obtained_expires==-1) { belle_sip_message("Neither Expires header nor corresponding Contact header found, checking from original request"); refresher->obtained_expires=refresher->target_expires; }else if (refresher->target_expires>0 && refresher->obtained_expires==0){ const char* reason = response ? belle_sip_response_get_reason_phrase(response) : NULL; /*check this case because otherwise we are going to loop fast in sending refresh requests.*/ /*"Test account created" is a special reason given by testers when we create temporary account. Since this is a bit of hack, we can ignore logging in that case*/ if (reason && strcmp(reason, "Test account created") != 0) { belle_sip_warning("Server replied with 0 expires, what does that mean?"); } /*suppose it's a server bug and assume our target_expires is understood.*/ refresher->obtained_expires=refresher->target_expires; } } else if (strcmp("INVITE",belle_sip_request_get_method(request))==0) { belle_sip_error("Refresher does not support INVITE yet"); return -1; } else { belle_sip_error("Refresher does not support [%s] yet",belle_sip_request_get_method(request)); return -1; } return 0; }
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); } }
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 ); } }
int sal_subscribe_accept(SalOp *op){ belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); belle_sip_response_t* resp = sal_op_create_response_from_request(op,req,200); belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires)); belle_sip_server_transaction_send_response(op->pending_server_trans,resp); return 0; }
int sal_message_reply(SalOp *op, SalReason reason){ if (op->pending_server_trans){ int code=sal_reason_to_sip_code(reason); belle_sip_response_t *resp = belle_sip_response_create_from_request( belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code); belle_sip_server_transaction_send_response(op->pending_server_trans,resp); return 0; }else ms_error("sal_message_reply(): no server transaction"); return -1; }
int sal_unsubscribe(SalOp *op){ if (op->refresher){ const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); sal_op_add_body(op,(belle_sip_message_t*)last_req,NULL); belle_sip_refresher_refresh(op->refresher,0); return 0; } return -1; }
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); } }
static void publish_refresher_listener ( const belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); if (status_code==412){ /*resubmit the request after removing the SIP-If-Match*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match"); belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); } }
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); } }
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); } }
/*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h){ belle_sip_response_t *response; belle_sip_header_contact_t* contact_header; belle_sip_server_transaction_t* transaction; /*first check if an UPDATE transaction need to be accepted*/ if (h->pending_update_server_trans) { transaction=h->pending_update_server_trans; } else if (h->pending_server_trans) { /*so it must be an invite/re-invite*/ transaction=h->pending_server_trans; } else { ms_error("No transaction to accept for op [%p]",h); return -1; } ms_message("Accepting server transaction [%p] on op [%p]", transaction, h); /* sends a 200 OK */ response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),200); if (response==NULL){ ms_error("Fail to build answer for call"); return -1; } belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow(h->base.root->enable_sip_update))); if (h->base.root->session_expires!=0){ /* if (h->supports_session_timers) {*/ belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Session-expires", "600;refresher=uac")); /*}*/ } if ((contact_header=sal_op_create_contact(h))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); } _sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response)); handle_offer_answer_response(h,response); belle_sip_server_transaction_send_response(transaction,response); if (h->pending_update_server_trans) { belle_sip_object_unref(h->pending_update_server_trans); h->pending_update_server_trans=NULL; } return 0; }
belle_sip_header_contact_t* belle_sip_refresher_get_contact(const belle_sip_refresher_t* refresher) { belle_sip_transaction_t* transaction = BELLE_SIP_TRANSACTION(refresher->transaction); belle_sip_request_t*request=belle_sip_transaction_get_request(transaction); belle_sip_response_t*response=transaction->last_response; const belle_sip_list_t* contact_header_list; belle_sip_header_contact_t* unfixed_local_contact; belle_sip_header_contact_t* fixed_local_contact; char* tmp_string; char* tmp_string2; if (!response) return NULL; /*we assume, there is only one contact in request*/ unfixed_local_contact= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t); fixed_local_contact= BELLE_SIP_HEADER_CONTACT(belle_sip_object_clone(BELLE_SIP_OBJECT(unfixed_local_contact))); /*first fix contact using received/rport*/ belle_sip_response_fix_contact(response,fixed_local_contact); contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list ,(belle_sip_compare_func)belle_sip_header_contact_not_equals , (const void*)fixed_local_contact); if (!contact_header_list) { /*reset header list*/ contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list ,(belle_sip_compare_func)belle_sip_header_contact_not_equals ,unfixed_local_contact); } if (!contact_header_list) { tmp_string=belle_sip_object_to_string(BELLE_SIP_OBJECT(fixed_local_contact)); tmp_string2=belle_sip_object_to_string(BELLE_SIP_OBJECT(unfixed_local_contact)); belle_sip_message("No matching contact neither for [%s] nor [%s]", tmp_string, tmp_string2); belle_sip_object_unref(fixed_local_contact); belle_sip_free(tmp_string); belle_sip_free(tmp_string2); return NULL; } else { belle_sip_object_unref(fixed_local_contact); return BELLE_SIP_HEADER_CONTACT(contact_header_list->data); } } else { return NULL; } }
belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm) { belle_sip_request_t* initial_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); belle_sip_request_t* req=belle_sip_request_clone_with_body(initial_request); belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_COMPLETED && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_TERMINATED) { belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED" ,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))) ,t); belle_sip_object_unref(req); return NULL; } /*remove auth headers*/ belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION); /*put auth header*/ belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm); return req; }
/*presence publish */ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){ belle_sip_request_t *req=NULL; if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { if (from) sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence); return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); } else { /*update presence status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),presence); return belle_sip_refresher_refresh(op->refresher,expires); } }
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; } }
static void publish_refresher_listener (belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op)); if (status_code==412){ /*resubmit the request after removing the SIP-If-Match*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match"); belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); }else if (status_code>=200){ SalError err; SalReason reason; sal_compute_sal_errors_from_code(status_code,&err,&reason); op->base.root->callbacks.on_publish_response(op,err,reason); } }
int belle_sip_refresher_start(belle_sip_refresher_t* refresher) { if(refresher->state==started) { belle_sip_warning("Refresher [%p] already started",refresher); } else { if (refresher->target_expires>0) { belle_sip_request_t* request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction)); refresher->state=started; if (is_contact_address_acurate(refresher,request)) { schedule_timer(refresher); /*re-arm timer*/ } else { belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher); belle_sip_refresher_refresh(refresher,refresher->target_expires); return 0; } belle_sip_message("Refresher [%p] started, next refresh in [%i] s",refresher,refresher->obtained_expires); }else{ belle_sip_message("Refresher [%p] stopped, expires=%i",refresher,refresher->target_expires); refresher->state=stopped; } } return 0; }
static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ int status; belle_sip_request_t* request; BELLESIP_UNUSED(user_ctx); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event)); belle_sip_message("process_response_event [%i] [%s]" ,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)) ,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event))); if (status==401){ belle_sip_header_cseq_t* cseq; belle_sip_client_transaction_t *t; belle_sip_uri_t *dest; // CU_ASSERT_NOT_EQUAL_FATAL(number_of_challenge,2); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_client_transaction(event)); /*require transaction mode*/ dest=belle_sip_client_transaction_get_route(belle_sip_response_event_get_client_transaction(event)); request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(belle_sip_response_event_get_client_transaction(event))); 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); 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); CU_ASSERT_TRUE_FATAL(belle_sip_provider_add_authorization(prov,request,belle_sip_response_event_get_response(event),NULL,NULL,auth_domain)); t=belle_sip_provider_create_client_transaction(prov,request); belle_sip_client_transaction_send_request_to(t,dest); number_of_challenge++; authorized_request=request; belle_sip_object_ref(authorized_request); } else { CU_ASSERT_EQUAL(status,200); is_register_ok=1; using_transaction=belle_sip_response_event_get_client_transaction(event)!=NULL; belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } }
bool_t sal_op_is_ipv6(SalOp *op){ belle_sip_transaction_t *tr=NULL; belle_sip_header_address_t *contact; if (op->refresher) tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher); if (tr==NULL) tr=(belle_sip_transaction_t *)op->pending_client_trans; if (tr==NULL) tr=(belle_sip_transaction_t *)op->pending_server_trans; if (tr==NULL){ ms_error("Unable to determine IP version from signaling operation."); return FALSE; } if (op->refresher) { belle_sip_response_t *resp = belle_sip_transaction_get_response(tr); belle_sip_header_via_t *via = resp ?belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t):NULL; if (!via){ ms_error("Unable to determine IP version from signaling operation, no via header found."); return FALSE; } return strchr(belle_sip_header_via_get_host(via),':') != NULL; } else { belle_sip_request_t *req = belle_sip_transaction_get_request(tr); contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); if (!contact){ ms_error("Unable to determine IP version from signaling operation, no contact header found."); } return sal_address_is_ipv6((SalAddress*)contact); } }