void linphone_xml_rpc_session_send_request(LinphoneXmlRpcSession *session, LinphoneXmlRpcRequest *request) { belle_http_request_listener_callbacks_t cbs = { 0 }; belle_http_request_listener_t *l; belle_generic_uri_t *uri; belle_http_request_t *req; belle_sip_memory_body_handler_t *bh; const char *data; linphone_xml_rpc_request_ref(request); uri = belle_generic_uri_parse(session->url); if (!uri) { ms_error("Could not send request, URL %s is invalid", session->url); process_io_error_from_post_xml_rpc_request(request, NULL); return; } req = belle_http_request_create("POST", uri, belle_sip_header_content_type_create("text", "xml"), NULL); if (!req) { belle_sip_object_unref(uri); process_io_error_from_post_xml_rpc_request(request, NULL); return; } data = linphone_xml_rpc_request_get_content(request); bh = belle_sip_memory_body_handler_new_copy_from_buffer(data, strlen(data), NULL, NULL); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh)); cbs.process_response = process_response_from_post_xml_rpc_request; cbs.process_io_error = process_io_error_from_post_xml_rpc_request; cbs.process_auth_requested = process_auth_requested_from_post_xml_rpc_request; l = belle_http_request_listener_create_from_callbacks(&cbs, request); belle_http_provider_send_request(session->core->http_provider, req, l); /*ensure that the listener object will be destroyed with the request*/ belle_sip_object_data_set(BELLE_SIP_OBJECT(request), "listener", l, belle_sip_object_unref); /*prevent destruction of the session while there are still pending http requests*/ belle_sip_object_data_set(BELLE_SIP_OBJECT(request), "session", belle_sip_object_ref(session), belle_sip_object_unref); }
void belle_sip_object_data_merge( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func) { struct _belle_sip_list* list = src->data_store; struct belle_sip_object_data* it = NULL; void* cloned_data = NULL; while( list ){ it = list->data; if( it ){ cloned_data = (clone_func)? clone_func( it->name, it->data ) : it->data; belle_sip_object_data_set(dst, it->name, cloned_data, it->destroy_func); } list = list->next; } }
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 test_object_data(void) { belle_sip_object_t* obj = belle_sip_object_new(belle_sip_object_t); belle_sip_object_t* cloned = belle_sip_object_new(belle_sip_object_t); int i = 123; const char* str = "toto", *str2 = "titi"; /* normal insertion with no destroy callback */ // should return 0 BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 0, int, "%d"); // should return the value we put in it BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i, int, "%d"); /* * Overwriting insertion */ // overwrite data: should return 1 when set() i = 124; BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 1 , int, "%d"); // should return the new value we put in it BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i, int, "%d"); /* * normal insertion with destroy callback */ BC_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str), test_object_data_string_destroy), 0, int, "%d"); // we should get back the same string BC_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"), str ); BC_ASSERT_EQUAL(belle_sip_object_data_remove(obj, "test_str"),0, int, "%d"); // we expect the destroy() function to be called on removal BC_ASSERT_EQUAL(destroy_called, 1, int, "%d"); destroy_called = 0; /* * string insertion and replace */ belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str), test_object_data_string_destroy); belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str2), test_object_data_string_destroy); BC_ASSERT_EQUAL(destroy_called, 1, int, "%d"); // we expect the dtor to have been called to free the first string /* * Get non-existent key */ BC_ASSERT_PTR_NULL(belle_sip_object_data_get(obj, "non-exist")); /* * test cloning the dictionary */ belle_sip_object_data_clone(obj, cloned, test_object_data_string_clone); BC_ASSERT_EQUAL(clone_called,2,int,"%d"); // we expect the clone function to be called for "test_i" and "test_st, int, "%d"r" // the values should be equal BC_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), VOIDPTR_TO_INT(belle_sip_object_data_get(cloned, "test_i")) , int, "%d"); BC_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"), (const char*)belle_sip_object_data_get(cloned, "test_str")); // but the pointers should be different BC_ASSERT_PTR_NOT_EQUAL( belle_sip_object_data_get(obj, "test_str"), belle_sip_object_data_get(cloned, "test_str")); /* * Foreach test */ belle_sip_object_data_foreach(obj, test_object_data_foreach_cb, NULL); BC_ASSERT_EQUAL( foreach_called, 2 , int, "%d"); belle_sip_object_unref(obj); belle_sip_object_unref(cloned); }