static unsigned int wait_for(belle_sip_stack_t *stack, int *current_value, int expected_value, int timeout) { #define ITER 100 uint64_t begin, end; begin = belle_sip_time_ms(); end = begin + timeout; while ((*current_value != expected_value) && (belle_sip_time_ms() < end)) { if (stack) belle_sip_stack_sleep(stack, ITER); } if (*current_value != expected_value) return FALSE; else return TRUE; }
int belle_sip_channel_notify_timeout(belle_sip_channel_t *obj){ const int too_long=60; if (belle_sip_time_ms() - obj->last_recv_time>=(too_long * 1000)){ belle_sip_message("A timeout related to this channel occured and no message received during last %i seconds. This channel is suspect, moving to error state",too_long); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); return TRUE; } return FALSE; }
void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){ if (source->node.next || source->node.prev){ belle_sip_fatal("Source is already linked somewhere else."); return; } if (source->node.data!=source){ belle_sip_fatal("Insane source passed to belle_sip_main_loop_add_source() !"); return; } belle_sip_object_ref(source); if (source->timeout>=0){ source->expire_ms=belle_sip_time_ms()+source->timeout; } ml->sources=belle_sip_list_append_link(ml->sources,&source->node); ml->nsources++; }
static void update_inactivity_timer(belle_sip_channel_t *obj, int from_recv){ int inactive_timeout=belle_sip_stack_get_inactive_transport_timeout(obj->stack)*1000; if (inactive_timeout>0){ if (!obj->inactivity_timer ){ obj->inactivity_timer=belle_sip_main_loop_create_timeout(obj->stack->ml,channel_inactive_timeout,obj,inactive_timeout,"Channel inactivity timer"); }else{ /*restart the timer for new period*/ belle_sip_source_set_timeout(obj->inactivity_timer,inactive_timeout); } }else{ if (obj->inactivity_timer){ belle_sip_main_loop_remove_source(obj->stack->ml,obj->inactivity_timer); belle_sip_object_unref(obj->inactivity_timer); obj->inactivity_timer=NULL; } } if (from_recv) obj->last_recv_time=belle_sip_time_ms(); }
void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){ size_t pfd_size = ml->nsources * sizeof(belle_sip_pollfd_t); belle_sip_pollfd_t *pfd=(belle_sip_pollfd_t*)belle_sip_malloc0(pfd_size); int i=0; belle_sip_source_t *s; belle_sip_list_t *elem,*next; uint64_t min_time_ms=(uint64_t)-1; int duration=-1; int ret; uint64_t cur; belle_sip_list_t *to_be_notified=NULL; int can_clean=belle_sip_object_pool_cleanable(ml->pool); /*iterate might not be called by the thread that created the main loop*/ belle_sip_object_pool_t *tmp_pool=NULL; if (!can_clean){ /*Push a temporary pool for the time of the iterate loop*/ tmp_pool=belle_sip_object_pool_push(); } /*Step 1: prepare the pollfd table and get the next timeout value */ for(elem=ml->sources;elem!=NULL;elem=next){ next=elem->next; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ belle_sip_source_to_poll(s,pfd,i); ++i; } if (s->timeout>=0){ if (min_time_ms>s->expire_ms){ min_time_ms=s->expire_ms; } } } } if (min_time_ms!=(uint64_t)-1 ){ int64_t diff; /* compute the amount of time to wait for shortest timeout*/ cur=belle_sip_time_ms(); diff=min_time_ms-cur; if (diff>0) duration=(int)diff; else duration=0; } /* do the poll */ ret=belle_sip_poll(pfd,i,duration); if (ret==-1){ goto end; } /* Step 2: examine poll results and determine the list of source to be notified */ cur=belle_sip_time_ms(); for(elem=ml->sources;elem!=NULL;elem=elem->next){ unsigned revents=0; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ if (s->notify_required) { /*for testing purpose to force channel to read*/ revents=BELLE_SIP_EVENT_READ; s->notify_required=0; /*reset*/ } else { revents=belle_sip_source_get_revents(s,pfd); } s->revents=revents; } if (revents!=0 || (s->timeout>=0 && cur>=s->expire_ms)){ to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); s->expired=TRUE; if (s->revents==0) s->revents=BELLE_SIP_EVENT_TIMEOUT; } }else to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); } /* Step 3: notify those to be notified */ for(elem=to_be_notified;elem!=NULL;){ s=(belle_sip_source_t*)elem->data; next=elem->next; if (!s->cancelled){ char *objdesc=belle_sip_object_to_string((belle_sip_object_t*)s); if (s->timeout>0)/*to avoid too many traces*/ belle_sip_debug("source %s notified revents=%u, timeout=%i",objdesc,revents,s->timeout); belle_sip_free(objdesc); ret=s->notify(s->data,s->revents); if (ret==BELLE_SIP_STOP || s->oneshot){ /*this source needs to be removed*/ belle_sip_main_loop_remove_source(ml,s); }else if (s->revents==BELLE_SIP_EVENT_TIMEOUT){ /*timeout needs to be started again */ s->expire_ms+=s->timeout; s->expired=FALSE; } }else belle_sip_main_loop_remove_source(ml,s); belle_sip_object_unref(s); belle_sip_free(elem); /*free just the element*/ elem=next; } if (can_clean) belle_sip_object_pool_clean(ml->pool); else if (tmp_pool) belle_sip_object_unref(tmp_pool); end: belle_sip_free(pfd); }
void belle_sip_source_set_timeout(belle_sip_source_t *s, unsigned int value_ms){ if (!s->expired){ s->expire_ms=belle_sip_time_ms()+value_ms; } s->timeout=value_ms; }
int main(int argc, char *argv[]){ char *str; struct stat st; int fd; int i; const char *filename=NULL; const char *protocol="sip"; if (argc<2){ fprintf(stderr,"Usage:\n%s [--protocol sip|http|sdp] <text file containing messages>\n",argv[0]); return -1; } for(i=1;i<argc;++i){ if (strcmp(argv[i],"--protocol")==0){ i++; if (i<argc){ protocol=argv[i]; }else{ fprintf(stderr,"Missing argument for --protocol\n"); return -1; } }else filename=argv[i]; } if (!filename){ fprintf(stderr,"No filename specified\n"); return -1; } if (stat(filename,&st)==-1){ fprintf(stderr,"Could not stat %s: %s\n",filename,strerror(errno)); return -1; } fd=open(filename,O_RDONLY); if (fd==-1){ fprintf(stderr,"Could not open %s: %s\n",filename,strerror(errno)); return -1; } str=belle_sip_malloc0(st.st_size+1); if (read(fd,str,st.st_size)==-1){ fprintf(stderr,"Could not read %s: %s\n",filename,strerror(errno)); belle_sip_free(str); close(fd); return -1; } close(fd); belle_sip_set_log_level(BELLE_SIP_LOG_DEBUG); for (i=0;i<st.st_size;){ size_t read; if (strcasecmp(protocol,"sip")==0 || strcasecmp(protocol,"http")==0){ belle_sip_message_t *msg; uint64_t begin,end; begin=belle_sip_time_ms(); msg=belle_sip_message_parse_raw(str+i,st.st_size-i,&read); end=belle_sip_time_ms(); if (msg){ printf("Successfully parsed %s message of %i bytes in %i ms.\n",protocol,(int)read, (int)(end-begin)); }else{ fprintf(stderr,"Failed to parse message.\n"); break; } i+=read; }else if (strcasecmp(protocol,"sdp")==0){ belle_sdp_session_description_t *sdp=belle_sdp_session_description_parse(str); if (sdp){ printf("Successfully parsed %s message of %i bytes.\n",protocol,(int)strlen(str)); }else{ fprintf(stderr,"Failed to parse SDP message.\n"); } break; } } belle_sip_free(str); return 0; }
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); }