int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) { if (sal_op_send_request_with_expires(op,req,expires)==0) { if (op->refresher) { belle_sip_refresher_stop(op->refresher); belle_sip_object_unref(op->refresher); } if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { /*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified * that it is terminated anymore.*/ sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/ /* Note that the refresher will replace our data with belle_sip_transaction_set_application_data(). Something in the design is not very good here, it makes things complicated to the belle-sip user. Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction notify the user as a normal transaction*/ belle_sip_refresher_set_listener(op->refresher,listener,op); belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); belle_sip_refresher_set_realm(op->refresher,op->base.realm); belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); return 0; } else { return -1; } } return -1; }
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_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) { if (sal_op_send_request_with_expires(op,req,expires)==0) { if (op->refresher) { belle_sip_refresher_stop(op->refresher); belle_sip_object_unref(op->refresher); } if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { belle_sip_refresher_set_listener(op->refresher,listener,op); belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); return 0; } else { return -1; } } return -1; }
static void subscribe_test(void) { belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; belle_sip_request_t* req; belle_sip_client_transaction_t* trans; belle_sip_header_route_t* destination_route; const char* identity = "sip:" USERNAME "@" SIPDOMAIN ; const char* domain="sip:" SIPDOMAIN ; endpoint_t* client,*server; belle_sip_uri_t *dest_uri; belle_sip_refresher_t* refresher; belle_sip_header_contact_t* contact=belle_sip_header_contact_new(); uint64_t begin; uint64_t end; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=0; server->auth=digest_auth; dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp)); belle_sip_uri_set_host(dest_uri,"127.0.0.1"); destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri)); req=belle_sip_request_create( belle_sip_uri_parse(domain), "SUBSCRIBE", belle_sip_provider_create_call_id(client->provider), belle_sip_header_cseq_create(20,"SUBSCRIBE"), belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG), belle_sip_header_to_create2(identity,NULL), belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_create("Event","Presence"))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route)); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/ belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000)); req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL); belle_sip_object_unref(trans); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans); belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); /*maybe dialog should be automatically created*/ CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(trans))) refresher = belle_sip_client_transaction_create_refresher(trans); belle_sip_object_unref(trans); belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client); begin = belle_sip_time_ms(); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,3,4000)); end = belle_sip_time_ms(); CU_ASSERT_TRUE(end-begin>=3000); CU_ASSERT_TRUE(end-begin<5000); /*unsubscribe twice to make sure refresh operation can be safely cascaded*/ belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_stop(refresher); belle_sip_object_unref(refresher); destroy_endpoint(client); destroy_endpoint(server); }
static void refresher_base_with_body(endpoint_t* client ,endpoint_t *server , const char* method , belle_sip_header_content_type_t* content_type ,const char* body) { belle_sip_request_t* req; belle_sip_client_transaction_t* trans; belle_sip_header_route_t* destination_route; belle_sip_refresher_t* refresher; const char* identity = "sip:" USERNAME "@" SIPDOMAIN ; const char* domain="sip:" SIPDOMAIN ; belle_sip_header_contact_t* contact=belle_sip_header_contact_new(); belle_sip_uri_t *dest_uri; uint64_t begin; uint64_t end; if (client->expire_in_contact) belle_sip_header_contact_set_expires(contact,1); dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp)); if (client->connection_family==AF_INET6) belle_sip_uri_set_host(dest_uri,"::1"); else belle_sip_uri_set_host(dest_uri,"127.0.0.1"); destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri)); req=belle_sip_request_create( belle_sip_uri_parse(domain), method, belle_sip_provider_create_call_id(client->provider), belle_sip_header_cseq_create(20,method), belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG), belle_sip_header_to_create2(identity,NULL), belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact)); if (!client->expire_in_contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route)); if (content_type && body) { size_t body_lenth=strlen(body); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(body_lenth))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),body,body_lenth); } trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/ belle_sip_client_transaction_send_request(trans); if (client->early_refresher) { client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans); } else { if (server->auth == none) { CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); } else { CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000)); /*update cseq*/ req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL); belle_sip_object_unref(trans); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans); belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); } client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans); } CU_ASSERT_TRUE_FATAL(refresher!=NULL); belle_sip_object_unref(trans); belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client); begin = belle_sip_time_ms(); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+(client->early_refresher?1:0),client->register_count*1000 + 1000)); end = belle_sip_time_ms(); CU_ASSERT_TRUE(end-begin>=client->register_count*1000*.9); /*because refresh is at 90% of expire*/ CU_ASSERT_TRUE(end-begin<(client->register_count*1000 + 2000)); /*unregister twice to make sure refresh operation can be safely cascaded*/ belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_refresh(refresher,0); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+1,1000)); CU_ASSERT_EQUAL(client->stat.refreshOk,client->register_count+1); belle_sip_refresher_stop(refresher); belle_sip_object_unref(refresher); }