Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
/*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;
}
Beispiel #7
0
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;
}