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 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); }
static void process_response_event(belle_sip_listener_t *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); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); int response_code = belle_sip_response_get_status_code(response); belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_header_contact_t *contact; if (refresher && (client_transaction !=refresher->transaction)) return; /*not for me*/ set_or_update_dialog(refresher,belle_sip_response_event_get_dialog(event)); /*success case:*/ if (response_code>=200 && response_code<300){ refresher->auth_failures=0; refresher->number_of_retry=0; /*great, success*/ if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) { /*search for etag*/ belle_sip_header_t* etag=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"SIP-ETag"); if (etag) { belle_sip_header_t* sip_if_match = belle_sip_header_create("SIP-If-Match",belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(etag))); /*update request for next refresh*/ belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),sip_if_match); } else if (refresher->target_expires > 0){ belle_sip_warning("Refresher [%p] received 200ok to a publish without etag",refresher); } } /*update expire if needed*/ set_expires_from_trans(refresher); if (refresher->target_expires<=0) { belle_sip_refresher_stop(refresher); /*doesn't not make sense to refresh if expire =0;*/ } else { /*remove all contact with expire = 0 from request if any, because no need to refresh them*/ const belle_sip_list_t * contact_list= belle_sip_message_get_headers(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT); belle_sip_list_t *iterator, *head; if (contact_list) { for (iterator=head=belle_sip_list_copy(contact_list);iterator!=NULL;iterator=iterator->next) { belle_sip_header_contact_t *contact_for_expire = (belle_sip_header_contact_t *)(iterator->data); if (belle_sip_header_contact_get_expires(contact_for_expire) == 0) { belle_sip_message_remove_header_from_ptr(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact_for_expire)); } } belle_sip_list_free(head); } } if (refresher->state==started) { if (!refresher->first_acknoleged_request) belle_sip_object_ref(refresher->first_acknoleged_request = request); 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; } } else belle_sip_message("Refresher [%p] not scheduling next refresh, because it was stopped",refresher); }else{/*special error cases*/ switch (response_code) { case 301: case 302: contact=belle_sip_message_get_header_by_type(response,belle_sip_header_contact_t); if (contact){ belle_sip_uri_t *uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact)); if (uri && belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,uri)==0) return; } break; case 401: case 407: refresher->auth_failures++; if (refresher->auth_failures>1){ /*avoid looping with 407 or 401 */ belle_sip_warning("Authentication is failing constantly, %s",(refresher->target_expires>0)? "will retry later":"giving up."); if (refresher->target_expires>0) retry_later(refresher); refresher->auth_failures=0; /*reset auth failure*/ break; } if (refresher->auth_events) { refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy); } if (belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,NULL)==0) return; /*ok, keep 401 internal*/ break; /*Else notify user of registration failure*/ case 403: /*In case of 403, we will retry later, just in case*/ if (refresher->target_expires>0) retry_later(refresher); break; case 412: if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match"); if (refresher->target_expires>0) { retry_later_on_io_error(refresher); return; /*do not notify this kind of error*/ } } else { if (refresher->target_expires>0) retry_later(refresher); } break; case 423:{ belle_sip_header_extension_t *min_expires=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header((belle_sip_message_t*)response,"Min-Expires")); if (min_expires){ const char *value=belle_sip_header_extension_get_value(min_expires); if (value){ int new_expires=atoi(value); if (new_expires>0 && refresher->state==started){ refresher->target_expires=new_expires; belle_sip_refresher_refresh(refresher,refresher->target_expires); return; } } }else belle_sip_warning("Receiving 423 but no min-expires header."); break; } case 491: { if (refresher->target_expires>0) { retry_later_on_io_error(refresher); return; /*do not notify this kind of error*/ } } case 505: case 501: /*irrecoverable errors, probably no need to retry later*/ break; default: /*for all other errors, retry later*/ if (refresher->target_expires>0) retry_later(refresher); break; } } if (refresher->listener) refresher->listener(refresher,refresher->user_data,response_code, belle_sip_response_get_reason_phrase(response)); }
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; } }