static void feed_body(belle_sip_channel_t *obj, size_t len){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); belle_sip_body_handler_recv_chunk(bh,msg,(uint8_t*)obj->input_stream.read_ptr,len); obj->input_stream.read_ptr+=len; belle_sip_channel_input_stream_rewind(&obj->input_stream); }
static int acquire_body_simple(belle_sip_channel_t *obj, int end_of_stream){ int content_length=obj->input_stream.content_length; size_t to_read=obj->input_stream.write_ptr-obj->input_stream.read_ptr; belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); size_t cursize=belle_sip_body_handler_get_transfered_size(bh); if ((cursize == 0) && (to_read == 0)) { /** * No data has been received yet, so do not call feed_body() with a size * of 0 that is meaning that the transfer is finished. */ } else { to_read=MIN(content_length-cursize, to_read); feed_body(obj,to_read); } if (end_of_stream || belle_sip_body_handler_get_transfered_size(bh)>=content_length){ /*great body completed*/ belle_sip_message("channel [%p] read [%i] bytes of body from [%s:%i]" ,obj ,content_length ,obj->peer_name ,obj->peer_port); belle_sip_channel_message_ready(obj); return BELLE_SIP_CONTINUE; } /*body is not finished, we need more data*/ return BELLE_SIP_STOP; }
static void belle_sip_channel_message_ready(belle_sip_channel_t *obj){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); if (bh) belle_sip_body_handler_end_transfer(bh); if (belle_sip_message_is_response(msg)) belle_sip_channel_learn_public_ip_port(obj,BELLE_SIP_RESPONSE(msg)); obj->incoming_messages=belle_sip_list_append(obj->incoming_messages,msg); belle_sip_channel_input_stream_reset(&obj->input_stream); }
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) { belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg); if (body_handler != NULL) { belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t); belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t); belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding"); if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type)); if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length)); if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding); } return (SalBodyHandler *)body_handler; }
static int acquire_body_simple(belle_sip_channel_t *obj, int end_of_stream){ int content_length=obj->input_stream.content_length; size_t to_read=obj->input_stream.write_ptr-obj->input_stream.read_ptr; belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); size_t cursize=belle_sip_body_handler_get_transfered_size(bh); to_read=MIN(content_length-cursize, to_read); feed_body(obj,to_read); if (end_of_stream || belle_sip_body_handler_get_transfered_size(bh)>=content_length){ /*great body completed belle_sip_message("channel [%p] read [%i] bytes of body from %s:%i\n%s" ,obj ,content_length ,obj->peer_name ,obj->peer_port ,obj->input_stream.read_ptr);*/ belle_sip_channel_message_ready(obj); return BELLE_SIP_CONTINUE; } /*body is not finished, we need more data*/ return BELLE_SIP_STOP; }
/*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; }
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; }