belle_sip_channel_t *belle_sip_listening_point_create_channel(belle_sip_listening_point_t *obj, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_listening_point_t)->create_channel(obj,hop); if (chan){ belle_sip_listening_point_add_channel(obj,chan); } return chan; }
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) { belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED); belle_sip_message("%s%s %s transaction [%p] terminated" ,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t)?"Client":"Server" ,t->is_internal?" internal":"" ,belle_sip_request_get_method(belle_sip_transaction_get_request(t)) ,t); BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); belle_sip_provider_set_transaction_terminated(t->provider,t); } }
void belle_sip_channel_connect(belle_sip_channel_t *obj){ char ip[64]; channel_set_state(obj,BELLE_SIP_CHANNEL_CONNECTING); belle_sip_addrinfo_to_ip(obj->current_peer,ip,sizeof(ip),NULL); belle_sip_message("Trying to connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),ip,obj->peer_port); if(BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->connect(obj,obj->current_peer)) { belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); } return; }
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) { int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t); belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED); if (t->dialog && (!t->last_response || belle_sip_response_get_status_code(t->last_response)<200)){ /*inform the dialog if a transaction terminates without final response.*/ belle_sip_dialog_update(t->dialog,t,!is_client); } belle_sip_message("%s%s %s transaction [%p] terminated" ,is_client ? "Client":"Server" ,t->is_internal ? " internal":"" ,belle_sip_request_get_method(belle_sip_transaction_get_request(t)) ,t); BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); belle_sip_provider_set_transaction_terminated(t->provider,t); } }
void belle_sip_listening_point_init(belle_sip_listening_point_t *lp, belle_sip_stack_t *s, const char *address, int port){ char *tmp; belle_sip_init_sockets(); lp->stack=s; lp->listening_uri=belle_sip_uri_create(NULL,address); belle_sip_object_ref(lp->listening_uri); belle_sip_uri_set_port(lp->listening_uri,port); belle_sip_uri_set_transport_param(lp->listening_uri,BELLE_SIP_OBJECT_VPTR(lp,belle_sip_listening_point_t)->transport); tmp=belle_sip_object_to_string((belle_sip_object_t*)BELLE_SIP_LISTENING_POINT(lp)->listening_uri); if (strchr(address,':')) { lp->ai_family=AF_INET6; } else { lp->ai_family=AF_INET; } belle_sip_message("Creating listening point [%p] on [%s]",lp, tmp); belle_sip_free(tmp); }
int belle_sip_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, uint8_t *buf, size_t *size){ int ret; if (obj->expected_size!=0){ *size=MIN(*size,obj->expected_size-obj->transfered_size); } ret=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_send(obj,msg,obj->transfered_size,buf,size); obj->transfered_size+=*size; update_progress(obj,msg); if (obj->expected_size!=0){ if (obj->transfered_size==obj->expected_size) return BELLE_SIP_STOP; if (ret==BELLE_SIP_STOP && obj->transfered_size<obj->expected_size){ belle_sip_error("body handler [%p] transfered only [%i] bytes while [%i] were expected",obj, (int)obj->transfered_size,(int)obj->expected_size); } } return ret; }
void belle_sip_channel_connect(belle_sip_channel_t *obj){ char ip[64]; int port=obj->peer_port; channel_set_state(obj,BELLE_SIP_CHANNEL_CONNECTING); belle_sip_addrinfo_to_ip(obj->current_peer,ip,sizeof(ip),&port); /* update peer_port as it may have been overriden by SRV resolution*/ if (port!=obj->peer_port){ /*the SRV resolution provided a port number that must be used*/ obj->srv_overrides_port=TRUE; obj->peer_port=port; } belle_sip_message("Trying to connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),ip,obj->peer_port); if(BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->connect(obj,obj->current_peer)) { belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); } return; }
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)t; belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to"); belle_sip_dialog_t *dialog=base->dialog; int status_code; belle_sip_object_ref(resp); if (!base->last_response){ belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp); base->channel=belle_sip_provider_get_channel(base->provider,hop); belle_sip_object_unref(hop); if (!base->channel){ belle_sip_error("Transaction [%p]: No channel available for sending response.",t); return; } belle_sip_object_ref(base->channel); belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t)); } status_code=belle_sip_response_get_status_code(resp); if (status_code!=100){ if (belle_sip_header_to_get_tag(to)==NULL){ //add a random to tag belle_sip_header_to_set_tag(to,t->to_tag); } /*12.1 Creation of a Dialog Dialogs are created through the generation of non-failure responses to requests with specific methods. Within this specification, only 2xx and 101-199 responses with a To tag, where the request was INVITE, will establish a dialog.*/ if (dialog && status_code>100 && status_code<300){ belle_sip_response_fill_for_dialog(resp,base->request); } } if (BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->send_new_response(t,resp)==0){ if (base->last_response) belle_sip_object_unref(base->last_response); base->last_response=resp; } if (dialog) belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE); }
void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){ const char *method=belle_sip_request_get_method(req); if (strcmp(method,"ACK")==0){ /*this must be for an INVITE server transaction */ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_ist_t)){ belle_sip_ist_t *ist=(belle_sip_ist_t*)t; if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){ belle_sip_dialog_t *dialog=t->base.dialog; if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0) server_transaction_notify(t,req,dialog); /*else nothing to do because retransmission of ACK*/ } }else{ belle_sip_warning("ACK received for non-invite server transaction ?"); } }else if (strcmp(method,"CANCEL")==0){ server_transaction_notify(t,req,t->base.dialog); }else BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t); }
LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config) { LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); int proto_version = LDAP_VERSION3; linphone_contact_provider_init((LinphoneContactProvider*)obj, lc); ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); if( !linphone_ldap_contact_provider_valid_config(config) ) { ms_error( "Invalid configuration for LDAP, aborting creation"); belle_sip_object_unref(obj); obj = NULL; } else { int ret; linphone_dictionary_foreach( config, linphone_ldap_contact_provider_config_dump_cb, 0 ); linphone_ldap_contact_provider_loadconfig(obj, config); ret = ldap_initialize(&(obj->ld),obj->server); if( ret != LDAP_SUCCESS ){ ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret)); belle_sip_object_unref(obj); obj = NULL; } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); belle_sip_object_unref(obj); obj = NULL; } else { // prevents blocking calls to bind() when the server is invalid, but this is not working for now.. // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509 //ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); // register our hook into iterate so that LDAP can do its magic asynchronously. linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } } return obj; }
static void on_channel_state_changed(belle_sip_channel_listener_t *l, belle_sip_channel_t *chan, belle_sip_channel_state_t state){ belle_sip_transaction_t *t=(belle_sip_transaction_t*)l; belle_sip_io_error_event_t ev; belle_sip_transaction_state_t tr_state=belle_sip_transaction_get_state((belle_sip_transaction_t*)t); belle_sip_message("transaction [%p] channel state changed to [%s]" ,t ,belle_sip_channel_state_to_string(state)); switch(state){ case BELLE_SIP_CHANNEL_READY: if (tr_state==BELLE_SIP_TRANSACTION_INIT && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ){ belle_sip_client_transaction_t *ct = (belle_sip_client_transaction_t*) t; BELLE_SIP_OBJECT_VPTR(ct,belle_sip_client_transaction_t)->send_request(ct); } break; case BELLE_SIP_CHANNEL_DISCONNECTED: case BELLE_SIP_CHANNEL_ERROR: ev.transport=belle_sip_channel_get_transport_name(chan); ev.source=BELLE_SIP_OBJECT(t); ev.port=chan->peer_port; ev.host=chan->peer_name; if ( tr_state!=BELLE_SIP_TRANSACTION_COMPLETED && tr_state!=BELLE_SIP_TRANSACTION_CONFIRMED && tr_state!=BELLE_SIP_TRANSACTION_ACCEPTED && tr_state!=BELLE_SIP_TRANSACTION_TERMINATED) { BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_io_error,&ev); } if (t->timed_out) notify_timeout((belle_sip_transaction_t*)t); belle_sip_transaction_terminate(t); break; default: /*ignored*/ break; } }
void belle_sip_channel_close(belle_sip_channel_t *obj){ if (BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->close) BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->close(obj); /*udp channel doesn't have close function*/ belle_sip_main_loop_remove_source(obj->stack->ml,(belle_sip_source_t*)obj); belle_sip_source_uninit((belle_sip_source_t*)obj); }
int belle_sip_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){ update_inactivity_timer(obj,TRUE); return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->channel_recv(obj,buf,buflen); }
int belle_sip_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){ update_inactivity_timer(obj,FALSE); return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->channel_send(obj,buf,buflen); }
const char * belle_sip_channel_get_transport_name(const belle_sip_channel_t *obj){ return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->transport; }
int belle_sip_channel_is_reliable(const belle_sip_channel_t *obj){ return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->reliable; }
void belle_sip_client_transaction_add_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){ BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->on_response(t,resp); }
int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy) { belle_sip_channel_t *chan; belle_sip_provider_t *prov=t->base.provider; belle_sip_dialog_t *dialog=t->base.dialog; belle_sip_request_t *req=t->base.request; int result=-1; if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){ belle_sip_error("belle_sip_client_transaction_send_request: bad state."); return -1; } /*check uris components compliance*/ if (!belle_sip_request_check_uris_components(t->base.request)) { belle_sip_error("belle_sip_client_transaction_send_request: bad request for transaction [%p]",t); return -1; } /*store preset route for future use by refresher*/ if (outbound_proxy){ t->preset_route=outbound_proxy; belle_sip_object_ref(t->preset_route); } if (t->base.sent_by_dialog_queue){ /*it can be sent immediately, so update the request with latest cseq and route_set */ /*update route and contact just in case they changed*/ belle_sip_dialog_update_request(dialog,req); } else if (t->base.request->dialog_queued){ /*this request was created by belle_sip_dialog_create_queued_request().*/ if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){ /*it cannot be sent immediately, queue the transaction into dialog*/ belle_sip_message("belle_sip_client_transaction_send_request(): transaction [%p], cannot send request now because dialog is busy" " or other transactions are queued, so queuing into dialog.",t); belle_sip_dialog_queue_client_transaction(dialog,t); return 0; } belle_sip_dialog_update_request(dialog,req); } if (dialog){ belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)); } if (!t->next_hop) { if (t->preset_route) { t->next_hop=belle_sip_hop_new_from_uri(t->preset_route); } else { t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request); } belle_sip_object_ref(t->next_hop); } else { /*next hop already preset, probably in case of CANCEL*/ } belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/ chan=belle_sip_provider_get_channel(prov,t->next_hop); if (chan){ belle_sip_object_ref(chan); belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t)); t->base.channel=chan; if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){ belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready"); belle_sip_channel_prepare(chan); /*the channel will notify us when it is ready*/ } else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){ /*otherwise we can send immediately*/ BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t); } result=0; }else { belle_sip_error("belle_sip_client_transaction_send_request(): no channel available"); belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t)); result=-1; } return result; }
void belle_sip_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, const uint8_t *buf, size_t size){ BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_recv(obj,msg,obj->transfered_size,buf,size); obj->transfered_size+=size; update_progress(obj,msg); }