/* belle-sip - SIP (RFC3261) library. Copyright (C) 2014 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" /* * Body handler base class implementation */ struct belle_sip_body_handler{ belle_sip_object_t base; belle_sip_body_handler_progress_callback_t progress_cb; size_t expected_size; /* 0 if unknown*/ size_t transfered_size; belle_sip_list_t *headers; /**> used when this body is part of a multipart message to store the header of this part */ char *headerStringBuffer; /**> buffer populated with a string created from marshaling the headers */ void *user_data; }; void belle_sip_body_handler_add_header(belle_sip_body_handler_t *obj, belle_sip_header_t *header) { if (header != NULL) { obj->headers=belle_sip_list_append(obj->headers,belle_sip_object_ref(header)); } } static void belle_sip_body_handler_clone(belle_sip_body_handler_t *obj, const belle_sip_body_handler_t *orig){ obj->progress_cb=orig->progress_cb; obj->user_data=orig->user_data; obj->expected_size=orig->expected_size; obj->transfered_size=orig->transfered_size; obj->headers=belle_sip_list_copy_with_data(orig->headers,(void *(*)(void*))belle_sip_object_clone_and_ref); if (orig->headerStringBuffer!=NULL) { obj->headerStringBuffer = strdup(orig->headerStringBuffer); } } static void belle_sip_body_handler_destroy(belle_sip_body_handler_t *obj){ belle_sip_list_free_with_data(obj->headers,belle_sip_object_unref); belle_sip_free(obj->headerStringBuffer); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_body_handler_t) { BELLE_SIP_VPTR_INIT(belle_sip_body_handler_t,belle_sip_object_t,TRUE), (belle_sip_object_destroy_t) belle_sip_body_handler_destroy, (belle_sip_object_clone_t) belle_sip_body_handler_clone, NULL,/*no marshal*/ }, NULL, /*chunk_recv*/ NULL /*chunk_send*/ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_body_handler_init(belle_sip_body_handler_t *obj, belle_sip_body_handler_progress_callback_t progress_cb, void *user_data){ obj->user_data=user_data; obj->progress_cb=progress_cb; obj->headers = NULL; /* header is not used in most of the case, set it using a dedicated function if needed */ obj->headerStringBuffer = NULL; /* header string buffer is set when adding a body handler to a multipart body handler */ } size_t belle_sip_body_handler_get_size(const belle_sip_body_handler_t *obj){ return obj->expected_size; } void belle_sip_body_handler_set_size(belle_sip_body_handler_t *obj, size_t size){ obj->expected_size=size; } size_t belle_sip_body_handler_get_transfered_size(const belle_sip_body_handler_t *obj){ return obj->transfered_size; } static void update_progress(belle_sip_body_handler_t *obj, belle_sip_message_t *msg){ if (obj->progress_cb) obj->progress_cb(obj,msg,obj->user_data,obj->transfered_size,obj->expected_size); } void belle_sip_body_handler_begin_transfer(belle_sip_body_handler_t *obj){ obj->transfered_size=0; } 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); } 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_sizeexpected_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_body_handler_end_transfer(belle_sip_body_handler_t *obj){ if (obj->expected_size==0) obj->expected_size=obj->transfered_size; } /* * memory body handler implementation. **/ struct belle_sip_memory_body_handler{ belle_sip_body_handler_t base; uint8_t *buffer; }; static void belle_sip_memory_body_handler_destroy(belle_sip_memory_body_handler_t *obj){ if (obj->buffer) belle_sip_free(obj->buffer); } static void belle_sip_memory_body_handler_clone(belle_sip_memory_body_handler_t *obj, const belle_sip_memory_body_handler_t *orig){ if (orig->buffer) { obj->buffer=belle_sip_malloc(orig->base.expected_size+1); memcpy(obj->buffer,orig->buffer,orig->base.expected_size); obj->buffer[orig->base.expected_size]='\0'; } } static void belle_sip_memory_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size){ belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base; obj->buffer=belle_sip_realloc(obj->buffer,offset+size+1); memcpy(obj->buffer+offset,buf,size); obj->buffer[offset+size]='\0'; } static int belle_sip_memory_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size){ belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base; size_t to_send=MIN(*size,obj->base.expected_size-offset); memcpy(buf,obj->buffer+offset,to_send); *size=to_send; return (obj->base.expected_size-offset==*size) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_memory_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_memory_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_memory_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_memory_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_memory_body_handler_clone, NULL }, belle_sip_memory_body_handler_recv_chunk, belle_sip_memory_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END const void *belle_sip_memory_body_handler_get_buffer(const belle_sip_memory_body_handler_t *obj){ return obj->buffer; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new(belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); return obj; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_from_buffer(void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); obj->buffer=(uint8_t*)buffer; obj->base.expected_size=bufsize; return obj; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_copy_from_buffer(const void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); obj->buffer=(uint8_t*)belle_sip_malloc(bufsize+1); obj->buffer[bufsize]='\0'; obj->base.expected_size=bufsize; memcpy(obj->buffer,buffer,bufsize); return obj; } /* * User body handler implementation */ struct belle_sip_user_body_handler{ belle_sip_body_handler_t base; belle_sip_user_body_handler_recv_callback_t recv_cb; belle_sip_user_body_handler_send_callback_t send_cb; }; static void belle_sip_user_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size){ belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base; if (obj->recv_cb) obj->recv_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size); else belle_sip_warning("belle_sip_user_body_handler_t ignoring received chunk."); } static int belle_sip_user_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size){ belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base; if (obj->send_cb) return obj->send_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size); else belle_sip_warning("belle_sip_user_body_handler_t ignoring send chunk."); *size=0; return BELLE_SIP_STOP; } static void belle_sip_user_body_handler_clone(belle_sip_user_body_handler_t *obj, const belle_sip_user_body_handler_t *orig){ obj->recv_cb=orig->recv_cb; obj->send_cb=orig->send_cb; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_user_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_user_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_user_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) NULL, (belle_sip_object_clone_t)belle_sip_user_body_handler_clone, NULL }, belle_sip_user_body_handler_recv_chunk, belle_sip_user_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_user_body_handler_t *belle_sip_user_body_handler_new( size_t total_size, belle_sip_body_handler_progress_callback_t progress_cb, belle_sip_user_body_handler_recv_callback_t recv_cb, belle_sip_user_body_handler_send_callback_t send_cb, void *data){ belle_sip_user_body_handler_t * obj=belle_sip_object_new(belle_sip_user_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data); obj->base.expected_size=total_size; obj->recv_cb=recv_cb; obj->send_cb=send_cb; return obj; } /** * File body handler implementation **/ struct belle_sip_file_body_handler{ belle_sip_body_handler_t base; char *filepath; }; static void belle_sip_file_body_handler_destroy(belle_sip_file_body_handler_t *obj) { if (obj->filepath) belle_sip_free(obj->filepath); } static void belle_sip_file_body_handler_clone(belle_sip_file_body_handler_t *obj, const belle_sip_file_body_handler_t *orig) { obj->filepath = belle_sip_strdup(orig->filepath); } static void belle_sip_file_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size) { FILE *f; int ret; belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base; if (obj->filepath == NULL) return; f = fopen(obj->filepath, "ab"); if (f == NULL) return; ret = fwrite(buf, 1, size, f); if (ret != size) { fclose(f); return; } fclose(f); } static int belle_sip_file_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size) { FILE *f; int ret; belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base; size_t to_send = MIN(*size, obj->base.expected_size - offset); if (obj->filepath == NULL) return BELLE_SIP_STOP; f = fopen(obj->filepath, "rb"); if (f == NULL) return BELLE_SIP_STOP; ret = fseek(f, offset, SEEK_SET); if (ret < 0) { fclose(f); return BELLE_SIP_STOP; } ret = fread(buf, 1, to_send, f); if (ret < 0) { fclose(f); return BELLE_SIP_STOP; } *size = ret; fclose(f); return (((obj->base.expected_size - offset) == *size) || (*size == 0)) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_file_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_file_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_file_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_file_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_file_body_handler_clone, NULL }, belle_sip_file_body_handler_recv_chunk, belle_sip_file_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_file_body_handler_t *belle_sip_file_body_handler_new(const char *filepath, belle_sip_body_handler_progress_callback_t progress_cb, void *data) { struct stat statbuf; belle_sip_file_body_handler_t *obj = belle_sip_object_new(belle_sip_file_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj, progress_cb, data); obj->filepath = belle_sip_strdup(filepath); if (stat(obj->filepath, &statbuf) == 0) { obj->base.expected_size = statbuf.st_size; } return obj; } /* * Multipart body handler implementation * TODO **/ #define MULTIPART_SEPARATOR "--" BELLESIP_MULTIPART_BOUNDARY "\r\n" #define MULTIPART_END "\r\n--" BELLESIP_MULTIPART_BOUNDARY "--\r\n" struct belle_sip_multipart_body_handler{ belle_sip_body_handler_t base; belle_sip_list_t *parts; }; static void belle_sip_multipart_body_handler_destroy(belle_sip_multipart_body_handler_t *obj){ belle_sip_list_free_with_data(obj->parts,belle_sip_object_unref); } static void belle_sip_multipart_body_handler_clone(belle_sip_multipart_body_handler_t *obj){ obj->parts=belle_sip_list_copy_with_data(obj->parts,(void *(*)(void*))belle_sip_object_clone_and_ref); } static void belle_sip_multipart_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, const uint8_t *buffer, size_t size){ /*TODO*/ } 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 */ belle_sip_body_handler_t *current_part = (belle_sip_body_handler_t *)obj_multipart->parts->data; *size -= strlen(MULTIPART_END); /* 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 */ 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(MULTIPART_SEPARATOR); 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, MULTIPART_SEPARATOR, offsetSize); /* 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 */ memcpy(buffer+*size, MULTIPART_END, strlen(MULTIPART_END)); *size+=strlen(MULTIPART_END); return BELLE_SIP_STOP; } } } return BELLE_SIP_STOP; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_multipart_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_multipart_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_multipart_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_multipart_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_multipart_body_handler_clone, NULL }, belle_sip_multipart_body_handler_recv_chunk, belle_sip_multipart_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_multipart_body_handler_t *belle_sip_multipart_body_handler_new(belle_sip_body_handler_progress_callback_t progress_cb, void *data, belle_sip_body_handler_t *first_part){ belle_sip_multipart_body_handler_t *obj=belle_sip_object_new(belle_sip_multipart_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data); obj->base.expected_size = strlen(MULTIPART_END); /* body's length will be part length(including boundary) + multipart end */ if (first_part) belle_sip_multipart_body_handler_add_part(obj,first_part); return obj; } #define DEFAULT_HEADER_STRING_SIZE 512 void belle_sip_multipart_body_handler_add_part(belle_sip_multipart_body_handler_t *obj, belle_sip_body_handler_t *part){ obj->base.expected_size+=part->expected_size+strlen(MULTIPART_SEPARATOR); /* add the separator length to the body length as each part start with a separator */ if (part->headers != NULL) { /* there is a declared header for this part, add its length to the expected total length */ size_t headerStringBufferSize = DEFAULT_HEADER_STRING_SIZE; size_t offset = 0; belle_sip_list_t *headerList = part->headers; part->headerStringBuffer = (char *)belle_sip_malloc(DEFAULT_HEADER_STRING_SIZE); while (headerList != NULL) { size_t offsetBackup=offset; /* we must backup the offset as it will be messed up by the marshal function in case of failure */ belle_sip_error_code returnCode = belle_sip_object_marshal(headerList->data, part->headerStringBuffer, headerStringBufferSize-5, &offset); /* -5 to leave room for carriage returns */ if (returnCode == BELLE_SIP_BUFFER_OVERFLOW) { /* increase buffer size */ offset=offsetBackup; /* restore the offset, no data were written to the buffer */ headerStringBufferSize+=DEFAULT_HEADER_STRING_SIZE; part->headerStringBuffer = (char *)belle_sip_realloc(part->headerStringBuffer, headerStringBufferSize); } else if (returnCode == BELLE_SIP_OK) { /* add the carriage return chars */ part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; headerList = belle_sip_list_next(headerList); } } part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; obj->base.expected_size += offset; part->headerStringBuffer[offset++]='\0'; /* null terminate the buffer in order to be able to get it length later using strlen */ } obj->parts=belle_sip_list_append(obj->parts,belle_sip_object_ref(part)); }