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 int belle_sip_multipart_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, uint8_t *buffer, size_t *size){ belle_sip_multipart_body_handler_t *obj_multipart=(belle_sip_multipart_body_handler_t*)obj; if (obj_multipart->parts->data) { /* we have a part, get its content from handler */ int retval = BELLE_SIP_STOP; size_t offsetSize = 0; /* used to store size of data added by this function and not given by the body handler of current part */ size_t boundary_len = strlen(obj_multipart->boundary); belle_sip_body_handler_t *current_part = (belle_sip_body_handler_t *)obj_multipart->parts->data; *size -= strlen(obj_multipart->boundary) + 8; /* just in case it will be the end of the message, ask for less characters than possible in order to be able to add the multipart message termination. 8 is for "\r\n--" and "--\r\n" */ if (current_part->transfered_size == 0) { /* Nothing transfered yet on this part, include a separator and the header if exists */ size_t headersSize = 0; offsetSize = strlen(obj_multipart->boundary) + 4; /* 4 is for "--" and "\r\n" */ if (current_part->headerStringBuffer != NULL) { headersSize = strlen(current_part->headerStringBuffer); } /* check if buffer is large enough to get the whole header + separtor and at least a byte of data */ if (*size < headersSize+offsetSize+1) { return BELLE_SIP_BUFFER_OVERFLOW; } /* insert separator */ memcpy(buffer, "--", 2); memcpy(buffer + 2, obj_multipart->boundary, boundary_len); memcpy(buffer + 2 + boundary_len, "\r\n", 2); offsetSize = boundary_len + 4; /* insert part header */ if (headersSize!=0) { memcpy(buffer+offsetSize, current_part->headerStringBuffer, headersSize); offsetSize += headersSize; } *size -=offsetSize; /* decrease data length requested to the current part handler */ } retval = belle_sip_body_handler_send_chunk(current_part, msg, buffer+offsetSize, size); /* add offsetSize to the buffer address in order to point at the begining of free space (after header if included) */ *size +=offsetSize; /* restore total of data given including potential separator and header */ if (retval == BELLE_SIP_CONTINUE) { return BELLE_SIP_CONTINUE; /* there is still data to be sent, continue */ } else { /* this part has reach the end, pass to next one if there is one */ if (obj_multipart->parts->next!=NULL) { /* there is an other part to be sent */ obj_multipart->parts = belle_sip_list_next(obj_multipart->parts); return BELLE_SIP_CONTINUE; } else { /* there is nothing else, close the message and return STOP */ size_t boundary_len = strlen(obj_multipart->boundary); memcpy(buffer + *size, "\r\n--", 4); memcpy(buffer + *size + 4, obj_multipart->boundary, boundary_len); memcpy(buffer + *size + 4 + boundary_len, "--\r\n", 4); *size+=boundary_len + 8; return BELLE_SIP_STOP; } } } return BELLE_SIP_STOP; }