/*copy the content of ref object to new object, for the part they have in common in their inheritence diagram*/ void _belle_sip_object_copy(belle_sip_object_t *newobj, const belle_sip_object_t *ref){ belle_sip_object_vptr_t *vptr; vptr=find_common_floor(newobj->vptr,ref->vptr); if (vptr==NULL){ belle_sip_fatal("Should not happen"); } while(vptr!=NULL){ if (vptr->clone==NULL){ belle_sip_fatal("Object of type %s cannot be cloned, it does not provide a clone() implementation.",vptr->type_name); return; }else vptr->clone(newobj,ref); vptr=vptr->get_parent(); } }
void belle_sip_object_pool_remove(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){ unsigned long tid=belle_sip_thread_self_id(); if (obj->pool!=pool){ belle_sip_fatal("Attempting to remove object from an incorrect pool: obj->pool=%p, pool=%p",obj->pool,pool); return; } if (tid!=pool->thread_id){ belle_sip_fatal("It is forbidden (and unsafe()) to ref()/unref() an unowned object outside of the thread that created it."); return; } pool->objects=belle_sip_list_delete_link(pool->objects,obj->pool_iterator); obj->pool_iterator=NULL; obj->pool=NULL; }
static belle_sip_error_code checked_marshal(belle_sip_object_vptr_t *vptr, belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset){ size_t tmp_buf_size=buff_size*2; char *p=(char*)belle_sip_malloc0(tmp_buf_size); size_t i; size_t initial_offset=*offset; belle_sip_error_code error=vptr->marshal(obj,p,buff_size,offset); size_t written; for (i=initial_offset;i<buff_size;++i){ if (p[i]=='\0') break; } written=i-initial_offset; if (error==BELLE_SIP_BUFFER_OVERFLOW){ belle_sip_error("Object of type %s commited a buffer overflow by marshalling %i bytes", vptr->type_name,(int)(*offset-initial_offset)); } else if (error!=BELLE_SIP_OK){ belle_sip_error("Object of type %s produced an error during marshalling: %i", vptr->type_name,error); } if (written!=(*offset-initial_offset) && written!=(buff_size-initial_offset-1)){ /*this is because snprintf won't allow you to write a non null character at the end of the buffer*/ belle_sip_fatal("Object of type %s marshalled %i bytes but said it marshalled %i bytes !", vptr->type_name,(int)written,(int)(*offset-initial_offset)); } memcpy(buff+initial_offset,p+initial_offset,*offset-initial_offset); belle_sip_free(p); return error; }
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++; }
void belle_sip_object_pool_add(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){ if (obj->pool!=NULL){ belle_sip_fatal("It is not possible to add an object to multiple pools."); } pool->objects=belle_sip_list_prepend(pool->objects,obj); obj->pool_iterator=pool->objects; obj->pool=pool; }
int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const char *local_tag, const char *remote_tag){ const char *dcid; if (obj->state==BELLE_SIP_DIALOG_NULL) belle_sip_fatal("_belle_sip_dialog_match() must not be used for dialog in null state."); dcid=belle_sip_header_call_id_get_call_id(obj->call_id); return strcmp(dcid,call_id)==0 && strcmp(obj->local_tag,local_tag)==0 && obj->remote_tag /* handle 180 without to tag */ && strcmp(obj->remote_tag,remote_tag)==0; }
static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; struct timeval tp; struct tm *lt; #ifndef _WIN32 struct tm tmstorage; #endif time_t curtime; belle_sip_gettimeofday(&tp,NULL); curtime=tp.tv_sec; #ifdef _WIN32 lt = localtime(&curtime); #else lt = localtime_r(&curtime,&tmstorage); #endif if (__log_file==NULL) __log_file=stderr; switch(lev){ case BELLE_SIP_LOG_DEBUG: lname="debug"; break; case BELLE_SIP_LOG_MESSAGE: lname="message"; break; case BELLE_SIP_LOG_WARNING: lname="warning"; break; case BELLE_SIP_LOG_ERROR: lname="error"; break; case BELLE_SIP_LOG_FATAL: lname="fatal"; break; default: belle_sip_fatal("Bad level !"); } msg=belle_sip_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) #ifndef _UNICODE OutputDebugStringA(msg); OutputDebugStringA("\r\n"); #else { int len=strlen(msg); wchar_t *tmp=(wchar_t*)belle_sip_malloc0((len+1)*sizeof(wchar_t)); mbstowcs(tmp,msg,len); OutputDebugStringW(tmp); OutputDebugStringW(L"\r\n"); belle_sip_free(tmp); } #endif #endif fprintf(__log_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i belle-sip-%s-%s" ENDLINE,1900+lt->tm_year,lt->tm_mon+1,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_sec,(int)(tp.tv_usec/1000), lname,msg); fflush(__log_file); free(msg); }
void *belle_sip_object_cast(belle_sip_object_t *obj, belle_sip_type_id_t id, const char *castname, const char *file, int fileno){ if (obj!=NULL){ if (has_type(obj,id)==0){ belle_sip_fatal("Bad cast to %s at %s:%i",castname,file,fileno); return NULL; } } return obj; }
void *belle_sip_object_interface_cast(belle_sip_object_t *obj, belle_sip_interface_id_t ifid, const char *castname, const char *file, int fileno){ if (obj!=NULL){ if (belle_sip_object_get_interface_methods(obj,ifid)==0){ belle_sip_fatal("Bad cast to interface %s at %s:%i",castname,file,fileno); return NULL; } } return obj; }
belle_sip_listening_point_t *belle_sip_stack_create_listening_point(belle_sip_stack_t *s, const char *ipaddress, int port, const char *transport){ belle_sip_listening_point_t *lp=NULL; if (strcasecmp(transport,"UDP")==0) { lp=belle_sip_udp_listening_point_new(s,ipaddress,port); } else if (strcasecmp(transport,"TCP") == 0) { lp=belle_sip_stream_listening_point_new(s,ipaddress,port); }else if (strcasecmp(transport,"TLS") == 0) { lp=belle_sip_tls_listening_point_new(s,ipaddress,port); } else { belle_sip_fatal("Unsupported transport %s",transport); } return lp; }
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){ const char *branch; belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via")); branch=belle_sip_header_via_get_branch(via); if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){ branch=req->rfc2543_branch; if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen."); } t->base.branch_id=belle_sip_strdup(branch); belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req); belle_sip_random_token(t->to_tag,sizeof(t->to_tag)); }
static void nict_set_completed(belle_sip_nict_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED); if (obj->timer_K) belle_sip_fatal("Should never happen."); belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); if (!belle_sip_channel_is_reliable(base->channel)){ obj->timer_K=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_K,obj,cfg->T4); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_K,"timer_K"); belle_sip_transaction_start_timer(base,obj->timer_K); }else belle_sip_transaction_terminate(base); }
void belle_sip_object_unref(void *ptr){ belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr); if (obj->ref==-1) belle_sip_fatal("Object with name [%s] freed twice !",obj->name); if (obj->ref==0 && obj->pool){ belle_sip_object_pool_remove(obj->pool,obj); obj->ref=-1; belle_sip_object_delete(obj); return; } obj->ref--; if (obj->ref==0){ obj->ref=-1; belle_sip_object_delete(obj); } }
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_client_transaction_init(belle_sip_client_transaction_t *obj, belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via")); char token[BELLE_SIP_BRANCH_ID_LENGTH]; if (!via){ belle_sip_fatal("belle_sip_client_transaction_init(): No via in request."); } if (strcmp(belle_sip_request_get_method(req),"CANCEL")!=0){ obj->base.branch_id=belle_sip_strdup_printf(BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",belle_sip_random_token(token,sizeof(token))); belle_sip_header_via_set_branch(via,obj->base.branch_id); }else{ obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via)); } belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req); }
void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); weak_ref_t *ref,*prevref=NULL,*next=NULL; if (o->ref==-1) return; /*too late and avoid recursions*/ for(ref=o->weak_refs;ref!=NULL;ref=next){ next=ref->next; if (ref->notify==destroy_notify && ref->userpointer==userpointer){ if (prevref==NULL) o->weak_refs=next; else prevref->next=next; belle_sip_free(ref); return; }else{ prevref=ref; } } belle_sip_fatal("Could not find weak_ref, you're a looser."); }
void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); weak_ref_t *ref,*prevref=NULL,*next=NULL; int found=FALSE; if (o->ref==-1) return; /*too late and avoid recursions*/ for(ref=o->weak_refs;ref!=NULL;ref=next){ next=ref->next; if (ref->notify==destroy_notify && ref->userpointer==userpointer){ if (prevref==NULL) o->weak_refs=next; else prevref->next=next; belle_sip_free(ref); found=TRUE; /*do not break or return, someone could have put twice the same weak ref on the same object*/ }else{ prevref=ref; } } if (!found) belle_sip_fatal("Could not find weak_ref, you're a looser."); }
void belle_sip_object_unref(void *ptr){ belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr); if (obj->ref==-1) { belle_sip_error("Object [%p] freed twice !",obj); if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name); if (obj->name) belle_sip_error("Object name might be [%s]",obj->name); belle_sip_fatal("Fatal object error encountered, aborting."); return; } if (obj->ref==0 && obj->pool){ belle_sip_object_pool_remove(obj->pool,obj); obj->ref=-1; belle_sip_object_delete(obj); return; } obj->ref--; if (obj->ref==0){ obj->ref=-1; belle_sip_object_delete(obj); } }
const char *belle_sip_transaction_state_to_string(belle_sip_transaction_state_t state){ switch(state){ case BELLE_SIP_TRANSACTION_INIT: return "INIT"; case BELLE_SIP_TRANSACTION_TRYING: return "TRYING"; case BELLE_SIP_TRANSACTION_CALLING: return "CALLING"; case BELLE_SIP_TRANSACTION_COMPLETED: return "COMPLETED"; case BELLE_SIP_TRANSACTION_CONFIRMED: return "CONFIRMED"; case BELLE_SIP_TRANSACTION_ACCEPTED: return "ACCEPTED"; case BELLE_SIP_TRANSACTION_PROCEEDING: return "PROCEEDING"; case BELLE_SIP_TRANSACTION_TERMINATED: return "TERMINATED"; } belle_sip_fatal("Invalid transaction state."); return "INVALID"; }
void belle_sip_object_pool_clean(belle_sip_object_pool_t *pool){ belle_sip_list_t *elem,*next; if (!belle_sip_object_pool_cleanable(pool)){ belle_sip_warning("Thread pool [%p] cannot be cleaned from thread [%lu] because it was created for thread [%lu]", pool,belle_sip_thread_self_id(),(unsigned long)pool->thread_id); return; } for(elem=pool->objects;elem!=NULL;elem=next){ belle_sip_object_t *obj=(belle_sip_object_t*)elem->data; if (obj->ref==0){ belle_sip_message("Garbage collecting unowned object of type %s",obj->vptr->type_name); obj->ref=-1; belle_sip_object_delete(obj); next=elem->next; belle_sip_free(elem); }else { belle_sip_fatal("Object %p is in unowned list but with ref count %i, bug.",obj,obj->ref); next=elem->next; } } pool->objects=NULL; }
static void _send_message(belle_sip_channel_t *obj){ char buffer[belle_sip_network_buffer_size]; size_t len=0; belle_sip_error_code error=BELLE_SIP_OK; belle_sip_message_t *msg=obj->cur_out_message; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); size_t body_len=bh ? belle_sip_body_handler_get_size(bh) : 0; int sendret; size_t off; int ret; if (obj->ewouldblock_buffer){ sendret=send_buffer(obj,(const char*)obj->ewouldblock_buffer+obj->ewouldblock_offset,obj->ewouldblock_size-obj->ewouldblock_offset); if (sendret>0){ obj->ewouldblock_offset+=sendret; if (obj->ewouldblock_offset==obj->ewouldblock_size){ free_ewouldblock_buffer(obj); } return; /*we prefer poll again to be sure we can write*/ }else if (belle_sip_error_code_is_would_block(-sendret)) { /*we got an ewouldblock again. Nothing to do, we'll be called later in order to retry*/ return; }else {/*error or disconnection case*/ goto done; } } if (obj->out_state==OUTPUT_STREAM_SENDING_HEADERS){ BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_sending,obj,msg); check_content_length(msg,body_len); error=belle_sip_object_marshal((belle_sip_object_t*)msg,buffer,sizeof(buffer)-1,&len); if (error!=BELLE_SIP_OK) { belle_sip_error("channel [%p] _send_message: marshaling failed.",obj); goto done; } /*send the headers and eventually the body if it fits in our buffer*/ if (bh){ size_t max_body_len=sizeof(buffer)-1-len; if (body_len>0 && body_len<=max_body_len){ /*if size is known and fits into our buffer, send together with headers*/ belle_sip_body_handler_begin_transfer(bh); do{ max_body_len=sizeof(buffer)-1-len; ret=belle_sip_body_handler_send_chunk(bh,msg,(uint8_t*)buffer+len,&max_body_len); len+=max_body_len; }while(ret==BELLE_SIP_CONTINUE); belle_sip_body_handler_end_transfer(bh); }else{ if (body_len==0){ belle_sip_fatal("Sending bodies whose size is not known must be done in chunked mode, which is not supported yet."); } belle_sip_body_handler_begin_transfer(bh); obj->out_state=OUTPUT_STREAM_SENDING_BODY; } } off=0; do{ sendret=send_buffer(obj,buffer+off,len-off); if (sendret>0){ off+=sendret; if (off==len){ break; } }else if (belle_sip_error_code_is_would_block(-sendret)) { handle_ewouldblock(obj,buffer+off,len-off); return; }else {/*error or disconnection case*/ goto done; } }while(1); } if (obj->out_state==OUTPUT_STREAM_SENDING_BODY){ do{ size_t chunk_len=sizeof(buffer)-1; ret=belle_sip_body_handler_send_chunk(bh,msg,(uint8_t*)buffer,&chunk_len); if (chunk_len!=0){ off=0; do{ sendret=send_buffer(obj,buffer+off,chunk_len-off); if (sendret>0){ off+=sendret; if (off==chunk_len){ break; } }else if (belle_sip_error_code_is_would_block(-sendret)) { handle_ewouldblock(obj,buffer+off,chunk_len-off); return; }else {/*error or disconnection case*/ goto done; } }while(1); } }while(ret==BELLE_SIP_CONTINUE); belle_sip_body_handler_end_transfer(bh); } done: /*we get ready to send another message*/ belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); free_ewouldblock_buffer(obj); obj->out_state=OUTPUT_STREAM_IDLE; belle_sip_object_unref(obj->cur_out_message); obj->cur_out_message=NULL; }
static void belle_sip_source_destroy(belle_sip_source_t *obj){ if (obj->node.next || obj->node.prev){ belle_sip_fatal("Destroying source currently used in main loop !"); } belle_sip_source_uninit(obj); }