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_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; }
int sal_op_refresh(SalOp *op) { if (op->refresher) { belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher)); return 0; } ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type)); 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; }
static int timer_cb(void *user_data, unsigned int events) { belle_sip_refresher_t* refresher = (belle_sip_refresher_t*)user_data; if (refresher->timer_purpose==NORMAL_REFRESH && refresher->manual) { belle_sip_message("Refresher [%p] is in manual mode, skipping refresh.",refresher); /*call listener with special code 0 to indicate request is about to expire*/ if (refresher->listener) refresher->listener(refresher,refresher->user_data,0, "about to expire"); return BELLE_SIP_STOP; } if (belle_sip_refresher_refresh(refresher,refresher->target_expires)==-1){ retry_later(refresher); } return BELLE_SIP_STOP; }
static void process_transaction_terminated(belle_sip_listener_t *user_ctx, const belle_sip_transaction_terminated_event_t *event) { belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_client_transaction_t*client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); if (refresher && (client_transaction !=refresher->transaction)) return; /*not for me*/ if (refresher->publish_pending && refresher->state==started) { refresher->publish_pending = FALSE; belle_sip_message("Publish pending on refresher [%p], doing it",refresher); belle_sip_refresher_refresh(refresher,refresher->target_expires); } else { refresher->publish_pending = FALSE; } }
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); } }
/*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_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 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 sal_register_refresh(SalOp *op, int expires){ if (op->refresher) return belle_sip_refresher_refresh(op->refresher,expires); else 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); }
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)); }