belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){ belle_sip_dialog_t *obj; belle_sip_header_from_t *from; const char *from_tag; belle_sip_header_to_t *to; const char *to_tag=NULL; from=belle_sip_message_get_header_by_type(t->request,belle_sip_header_from_t); if (from==NULL){ belle_sip_error("belle_sip_dialog_new(): no from!"); return NULL; } from_tag=belle_sip_header_from_get_tag(from); if (from_tag==NULL){ belle_sip_error("belle_sip_dialog_new(): no from tag!"); return NULL; } if (t->last_response) { to=belle_sip_message_get_header_by_type(t->last_response,belle_sip_header_to_t); if (to==NULL){ belle_sip_error("belle_sip_dialog_new(): no to!"); return NULL; } to_tag=belle_sip_header_to_get_tag(to); } obj=belle_sip_object_new(belle_sip_dialog_t); obj->terminate_on_bye=1; obj->provider=t->provider; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)){ obj->remote_tag=belle_sip_strdup(from_tag); obj->local_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=TRUE; }else{ const belle_sip_list_t *predefined_routes=NULL; obj->local_tag=belle_sip_strdup(from_tag); obj->remote_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=FALSE; for(predefined_routes=belle_sip_message_get_headers((belle_sip_message_t*)t->request,BELLE_SIP_ROUTE); predefined_routes!=NULL;predefined_routes=predefined_routes->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(predefined_routes->data)); } } belle_sip_message("New %s dialog [%p] , local tag [%s], remote tag [%s]" ,obj->is_server?"server":"client" ,obj ,obj->local_tag?obj->local_tag:"" ,obj->remote_tag?obj->remote_tag:""); set_state(obj,BELLE_SIP_DIALOG_NULL); return obj; }
static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ belle_sip_header_contact_t* newct; /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); newct = sal_op_create_contact(op); belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); return; } /*if a header already exists in the message, replace it*/ belle_sip_message_set_header(msg,h); }
const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ if (ch){ belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); if (h){ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){ return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h)); }else{ return belle_sip_header_get_unparsed_value(h); } } } return NULL; }
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ belle_sip_client_transaction_t*client_transaction; SalOp* op; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); if (op->callbacks.process_io_error) { op->callbacks.process_io_error(op,event); } } else { /*ms_error("sal process_io_error not implemented yet for non transaction");*/ /*nop, because already handle at transaction layer*/ } }
/*returns TRUE if a body is expected, and initialize a few things in the input stream context*/ static int check_body(belle_sip_channel_t *obj){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_header_content_length_t* content_length_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t); int expect_body=FALSE; obj->input_stream.content_length= content_length_header ? belle_sip_header_content_length_get_content_length(content_length_header) : 0; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_sip_response_t) || BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_sip_request_t)){ expect_body=obj->input_stream.content_length>0; }else{/*http*/ if (belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t)!=NULL){ belle_sip_header_t *transfer_encoding=belle_sip_message_get_header(msg,"Transfer-Encoding"); if (transfer_encoding){ const char *value=belle_sip_header_get_unparsed_value(transfer_encoding); if (strstr(value,"chunked")!=0){ obj->input_stream.chuncked_mode=1; obj->input_stream.content_length=0; obj->input_stream.chunk_size=-1; obj->input_stream.chunk_read_size=0; } } expect_body=TRUE; } } if (expect_body){ belle_sip_body_handler_t *bh; /*should notify the listeners*/ BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_message_headers,obj,msg); /*check if the listener has setup a body handler, otherwise create a default one*/ if ((bh=belle_sip_message_get_body_handler(msg))==NULL){ belle_sip_message_set_body_handler(msg,(bh=(belle_sip_body_handler_t*)belle_sip_memory_body_handler_new(NULL,NULL))); } belle_sip_body_handler_begin_transfer(bh); } return expect_body; }
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 channel_parser_tester_recovery_from_error_base (const char* prelude,const char* raw_message) { belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , 45421 , NULL , "127.0.0.1" , 45421); belle_sip_request_t* request; belle_sip_message_t* message; if (prelude) { channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,prelude); channel->input_stream.write_ptr+=strlen(prelude); belle_sip_channel_parse_stream(channel,FALSE); } channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,FALSE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_sip_request_t)); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Expires")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_EXPIRES(belle_sip_message_get_header(message,"Expires"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Proxy-Authorization")); check_uri_and_headers(message); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(stack); }
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); }
int belle_sip_dialog_is_authorized_transaction(const belle_sip_dialog_t *dialog,const char* method) { if (belle_sip_dialog_request_pending(dialog)){ const char* last_transaction_request; if (strcasecmp(method,"BYE")==0) return TRUE; /*don't reject a BYE*/ last_transaction_request = belle_sip_request_get_method(belle_sip_transaction_get_request(dialog->last_transaction)); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(dialog->last_transaction,belle_sip_client_transaction_t) && strcmp(last_transaction_request,"SUBSCRIBE")==0 && strcmp(method,"NOTIFY")==0){ /*stupid as it is, you have to accept a NOTIFY for a SUBSCRIBE for which no answer is received yet...*/ return TRUE; } if (strcmp(last_transaction_request,"INVITE")==0 && (strcmp(method,"PRACK")==0 || strcmp(method,"UPDATE")==0)){ /*PRACK /UPDATE needs to be sent or received during reINVITEs.*/ return TRUE; } return FALSE; } else { return TRUE; } }
void channel_parser_http_response () { belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , 45421 , NULL , "127.0.0.1" , 45421); const char * raw_message= "HTTP/1.1 200 OK\r\n" "Cache-Control: private\r\n" "Date: Tue, 07 Jan 2014 13:51:57 GMT\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Server: Microsoft-IIS/6.0\r\n" "X-Powered-By: ASP.NET\r\n" "Content-Encoding: gzip\r\n" "Vary: Accept-Encoding\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" "<html></html>\r\n\r\n"; belle_http_response_t* response; belle_sip_message_t* message; channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,TRUE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_http_response_t)); response = BELLE_HTTP_RESPONSE(message); CU_ASSERT_STRING_EQUAL(belle_http_response_get_reason_phrase(response),"OK"); CU_ASSERT_EQUAL(belle_http_response_get_status_code(response),200); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Cache-Control")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Vary")); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(stack); }
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; } }
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; }
static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_uri_t* outbound_proxy=NULL; belle_sip_header_contact_t* contact; int result =-1; belle_sip_uri_t *next_hop_uri=NULL; if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) { contact = sal_op_create_contact(op); belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); } /*keep existing*/ _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { /*don't put route header if dialog is in confirmed state*/ const MSList *elem=sal_op_get_route_addresses(op); const char *transport; const char *method=belle_sip_request_get_method(request); belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP"); if (elem) { outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); next_hop_uri=outbound_proxy; }else{ next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); } transport=belle_sip_uri_get_transport_param(next_hop_uri); if (transport==NULL){ /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use * the first available transport*/ if (!belle_sip_uri_is_secure(next_hop_uri)){ if (udplp==NULL){ if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ transport="tcp"; }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ transport="tls"; } } if (transport){ belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); belle_sip_uri_set_transport_param(next_hop_uri,transport); } } }else{ #ifdef TUNNEL_ENABLED if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){ /* our tunnel mode only supports UDP. Force transport to be set to UDP */ belle_sip_uri_set_transport_param(next_hop_uri,"udp"); } #endif } if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); } } client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_object_ref(op->pending_client_trans); if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm); } result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); /*update call id if not set yet for this OP*/ if (result == 0 && !op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t)))); } return result; }