/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 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 3 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" #include #include "clock_gettime.h" /*for apple*/ static FILE *__log_file=0; /** *@param file a FILE pointer where to output the belle logs. * **/ void belle_sip_set_log_file(FILE *file) { __log_file=file; } static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args); belle_sip_log_function_t belle_sip_logv_out=__belle_sip_logv_out; /** *@param func: your logging function, compatible with the OrtpLogFunc prototype. * **/ void belle_sip_set_log_handler(belle_sip_log_function_t func){ belle_sip_logv_out=func; } unsigned int __belle_sip_log_mask=BELLE_SIP_LOG_WARNING|BELLE_SIP_LOG_ERROR|BELLE_SIP_LOG_FATAL; /** * @ param level: either BELLE_SIP_LOG_DEBUG, BELLE_SIP_LOG_MESSAGE, BELLE_SIP_LOG_WARNING, BELLE_SIP_LOG_ERROR * BELLE_SIP_LOG_FATAL . **/ void belle_sip_set_log_level(int level){ __belle_sip_log_mask=(level<<1)-1; } char * belle_sip_strdup_vprintf(const char *fmt, va_list ap) { /* Guess we need no more than 100 bytes. */ int n, size = 200; char *p,*np; #ifndef WIN32 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ #endif if ((p = (char *) malloc (size)) == NULL) return NULL; while (1) { /* Try to print in the allocated space. */ #ifndef WIN32 va_copy(cap,ap); n = vsnprintf (p, size, fmt, cap); va_end(cap); #else /*this works on 32 bits, luckily*/ n = vsnprintf (p, size, fmt, ap); #endif /* If that worked, return the string. */ if (n > -1 && n < size) return p; //printf("Reallocing space.\n"); /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n + 1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((np = (char *) realloc (p, size)) == NULL) { free(p); return NULL; } else { p = np; } } } char *belle_sip_strdup_printf(const char *fmt,...){ char *ret; va_list args; va_start (args, fmt); ret=belle_sip_strdup_vprintf(fmt, args); va_end (args); return ret; } #if defined(WIN32) || defined(_WIN32_WCE) #define ENDLINE "\r\n" #else #define ENDLINE "\n" #endif #if defined(WIN32) || defined(_WIN32_WCE) void belle_sip_logv(int level, const char *fmt, va_list args) { if (belle_sip_logv_out!=NULL && belle_sip_log_level_enabled(level)) belle_sip_logv_out(level,fmt,args); #if !defined(_WIN32_WCE) if ((level)==BELLE_SIP_FATAL) abort(); #endif } #endif static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; if (__log_file==NULL) __log_file=stderr; switch(lev){ case BELLE_SIP_LOG_DEBUG: lname="debug"; break; case BELLE_SIP_LOG_MESSAGE: lname="message"; break; case BELLE_SIP_LOG_WARNING: lname="warning"; break; case BELLE_SIP_LOG_ERROR: lname="error"; break; case BELLE_SIP_LOG_FATAL: lname="fatal"; break; default: belle_sip_fatal("Bad level !"); } msg=belle_sip_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) OutputDebugString(msg); OutputDebugString("\r\n"); #endif fprintf(__log_file,"belle-sip-%s-%s" ENDLINE,lname,msg); fflush(__log_file); free(msg); } belle_sip_list_t* belle_sip_list_new(void *data){ belle_sip_list_t* new_elem=belle_sip_new0(belle_sip_list_t); new_elem->data=data; return new_elem; } belle_sip_list_t* belle_sip_list_append_link(belle_sip_list_t* elem,belle_sip_list_t *new_elem){ belle_sip_list_t* it=elem; if (elem==NULL) return new_elem; while (it->next!=NULL) it=belle_sip_list_next(it); it->next=new_elem; new_elem->prev=it; return elem; } belle_sip_list_t* belle_sip_list_append(belle_sip_list_t* elem, void * data){ belle_sip_list_t* new_elem=belle_sip_list_new(data); return belle_sip_list_append_link(elem,new_elem); } belle_sip_list_t* belle_sip_list_prepend(belle_sip_list_t* elem, void *data){ belle_sip_list_t* new_elem=belle_sip_list_new(data); if (elem!=NULL) { new_elem->next=elem; elem->prev=new_elem; } return new_elem; } belle_sip_list_t * belle_sip_list_last_elem(const belle_sip_list_t *l){ if (l==NULL) return NULL; while(l->next){ l=l->next; } return (belle_sip_list_t*)l; } belle_sip_list_t* belle_sip_list_concat(belle_sip_list_t* first, belle_sip_list_t* second){ belle_sip_list_t* it=first; if (it==NULL) return second; while(it->next!=NULL) it=belle_sip_list_next(it); it->next=second; second->prev=it; return first; } belle_sip_list_t* belle_sip_list_free(belle_sip_list_t* list){ belle_sip_list_t* elem = list; belle_sip_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; belle_sip_free(tmp); } belle_sip_free(elem); return NULL; } belle_sip_list_t * belle_sip_list_free_with_data(belle_sip_list_t *list, void (*freefunc)(void*)){ belle_sip_list_t* elem = list; belle_sip_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; freefunc(tmp->data); belle_sip_free(tmp); } freefunc(elem->data); belle_sip_free(elem); return NULL; } belle_sip_list_t* belle_sip_list_remove(belle_sip_list_t* first, void *data){ belle_sip_list_t* it; it=belle_sip_list_find(first,data); if (it) return belle_sip_list_delete_link(first,it); else { belle_sip_warning("belle_sip_list_remove: no element with %p data was in the list", data); return first; } } int belle_sip_list_size(const belle_sip_list_t* first){ int n=0; while(first!=NULL){ ++n; first=first->next; } return n; } void belle_sip_list_for_each(const belle_sip_list_t* list, void (*func)(void *)){ for(;list!=NULL;list=list->next){ func(list->data); } } void belle_sip_list_for_each2(const belle_sip_list_t* list, void (*func)(void *, void *), void *user_data){ for(;list!=NULL;list=list->next){ func(list->data,user_data); } } belle_sip_list_t* belle_sip_list_remove_link(belle_sip_list_t* list, belle_sip_list_t* elem){ belle_sip_list_t* ret; if (elem==list){ ret=elem->next; elem->prev=NULL; elem->next=NULL; if (ret!=NULL) ret->prev=NULL; return ret; } elem->prev->next=elem->next; if (elem->next!=NULL) elem->next->prev=elem->prev; elem->next=NULL; elem->prev=NULL; return list; } belle_sip_list_t * belle_sip_list_delete_link(belle_sip_list_t* list, belle_sip_list_t* elem){ belle_sip_list_t *ret=belle_sip_list_remove_link(list,elem); belle_sip_free(elem); return ret; } belle_sip_list_t* belle_sip_list_find(belle_sip_list_t* list, void *data){ for(;list!=NULL;list=list->next){ if (list->data==data) return list; } return NULL; } belle_sip_list_t* belle_sip_list_find_custom(belle_sip_list_t* list, belle_sip_compare_func compare_func, const void *user_data){ for(;list!=NULL;list=list->next){ if (compare_func(list->data,user_data)==0) return list; } return NULL; } belle_sip_list_t *belle_sip_list_delete_custom(belle_sip_list_t *list, belle_sip_compare_func compare_func, const void *user_data){ belle_sip_list_t *elem=belle_sip_list_find_custom(list,compare_func,user_data); if (elem!=NULL){ list=belle_sip_list_delete_link(list,elem); } return list; } void * belle_sip_list_nth_data(const belle_sip_list_t* list, int index){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (i==index) return list->data; } belle_sip_error("belle_sip_list_nth_data: no such index in list."); return NULL; } int belle_sip_list_position(const belle_sip_list_t* list, belle_sip_list_t* elem){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (elem==list) return i; } belle_sip_error("belle_sip_list_position: no such element in list."); return -1; } int belle_sip_list_index(const belle_sip_list_t* list, void *data){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (data==list->data) return i; } belle_sip_error("belle_sip_list_index: no such element in list."); return -1; } belle_sip_list_t* belle_sip_list_insert_sorted(belle_sip_list_t* list, void *data, int (*compare_func)(const void *, const void*)){ belle_sip_list_t* it,*previt=NULL; belle_sip_list_t* nelem; belle_sip_list_t* ret=list; if (list==NULL) return belle_sip_list_append(list,data); else{ nelem=belle_sip_list_new(data); for(it=list;it!=NULL;it=it->next){ previt=it; if (compare_func(data,it->data)<=0){ nelem->prev=it->prev; nelem->next=it; if (it->prev!=NULL) it->prev->next=nelem; else{ ret=nelem; } it->prev=nelem; return ret; } } previt->next=nelem; nelem->prev=previt; } return ret; } belle_sip_list_t* belle_sip_list_insert(belle_sip_list_t* list, belle_sip_list_t* before, void *data){ belle_sip_list_t* elem; if (list==NULL || before==NULL) return belle_sip_list_append(list,data); for(elem=list;elem!=NULL;elem=belle_sip_list_next(elem)){ if (elem==before){ if (elem->prev==NULL) return belle_sip_list_prepend(list,data); else{ belle_sip_list_t* nelem=belle_sip_list_new(data); nelem->prev=elem->prev; nelem->next=elem; elem->prev->next=nelem; elem->prev=nelem; } } } return list; } belle_sip_list_t* belle_sip_list_copy(const belle_sip_list_t* list){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,iter->data); } return copy; } belle_sip_list_t* belle_sip_list_copy_with_data(const belle_sip_list_t* list, void* (*copyfunc)(void*)){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,copyfunc(iter->data)); } return copy; } char * belle_sip_concat (const char *str, ...) { va_list ap; size_t allocated = 100; char *result = (char *) malloc (allocated); if (result != NULL) { char *newp; char *wp; const char* s; va_start (ap, str); wp = result; for (s = str; s != NULL; s = va_arg (ap, const char *)) { size_t len = strlen (s); /* Resize the allocated memory if necessary. */ if (wp + len + 1 > result + allocated) { allocated = (allocated + len) * 2; newp = (char *) realloc (result, allocated); if (newp == NULL) { free (result); return NULL; } wp = newp + (wp - result); result = newp; } memcpy (wp, s, len); wp +=len; } /* Terminate the result string. */ *wp++ = '\0'; /* Resize memory to the optimal size. */ newp = realloc (result, wp - result); if (newp != NULL) result = newp; va_end (ap); } return result; } void *belle_sip_malloc(size_t size){ return malloc(size); } void *belle_sip_malloc0(size_t size){ void *p=malloc(size); memset(p,0,size); return p; } void *belle_sip_realloc(void *ptr, size_t size){ return realloc(ptr,size); } void belle_sip_free(void *ptr){ free(ptr); } char * belle_sip_strdup(const char *s){ return strdup(s); } uint64_t belle_sip_time_ms(void){ struct timespec ts; static int clock_id=CLOCK_MONOTONIC; if (clock_gettime(clock_id,&ts)==-1){ belle_sip_error("clock_gettime() error for clock_id=%i: %s",clock_id,strerror(errno)); if (clock_id==CLOCK_MONOTONIC){ clock_id=CLOCK_REALTIME; return belle_sip_time_ms(); } return 0; } return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL); } /** * parser parameter pair */ belle_sip_param_pair_t* belle_sip_param_pair_new(const char* name,const char* value) { belle_sip_param_pair_t* lPair = (belle_sip_param_pair_t*)belle_sip_new0(belle_sip_param_pair_t); lPair->name=name?belle_sip_strdup(name):NULL; lPair->value=value?belle_sip_strdup(value):NULL; return lPair; } void belle_sip_param_pair_destroy(belle_sip_param_pair_t* pair) { if (pair->name) belle_sip_free(pair->name); if (pair->value) belle_sip_free(pair->value); belle_sip_free (pair); } int belle_sip_param_pair_comp_func(const belle_sip_param_pair_t *a, const char*b) { return strcmp(a->name,b); } char* _belle_sip_str_dup_and_unquote_string(const char* quoted_string) { size_t value_size = strlen(quoted_string); char* unquoted_string = belle_sip_malloc0(value_size-2+1); strncpy(unquoted_string,quoted_string+1,value_size-2); return unquoted_string; } unsigned int belle_sip_random(void){ #ifdef __linux static int fd=-1; if (fd==-1) fd=open("/dev/urandom",O_RDONLY); if (fd!=-1){ unsigned int tmp; if (read(fd,&tmp,4)!=4){ belle_sip_error("Reading /dev/urandom failed."); }else return tmp; }else belle_sip_error("Could not open /dev/urandom"); #endif return (unsigned int) random(); } /** * Write a random text token of supplied size. **/ char * belle_sip_random_token(char *ret, size_t size){ static const char *symbols="aAbBcCdDeEfFgGhHiIjJkKlLmMnN0pPqQrRsStTuUvVwWxXyYzZ"; unsigned int val; int i,j; for(i=0,j=0;i>5; } ret[i]=0; return ret; } void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple){ const belle_sip_list_t *elem; elem=belle_sip_message_get_headers(orig,header); for (;elem!=NULL;elem=elem->next){ belle_sip_header_t *ref_header=(belle_sip_header_t*)elem->data; if (ref_header){ ref_header=(belle_sip_header_t*)belle_sip_object_clone((belle_sip_object_t*)ref_header); if (!multiple){ belle_sip_message_set_header(dest,ref_header); break; }else belle_sip_message_add_header(dest,ref_header); } } }