belle_sip_object.c 25.4 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2
/*
	belle-sip - SIP (RFC3261) library.
3
	Copyright (C) 2010  Belledonne Communications SARL
Simon Morlat's avatar
Simon Morlat committed
4

5 6
	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
7
	the Free Software Foundation, either version 2 of the License, or
8
	(at your option) any later version.
Simon Morlat's avatar
Simon Morlat committed
9

10 11 12 13
	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.
Simon Morlat's avatar
Simon Morlat committed
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
Simon Morlat's avatar
Simon Morlat committed
17 18 19 20
*/

#include "belle_sip_internal.h"

Simon Morlat's avatar
Simon Morlat committed
21
static void _belle_sip_object_pool_remove_from_stack(belle_sip_object_pool_t *pool);
22

23 24
static int _belle_sip_object_marshal_check_enabled = FALSE;

Simon Morlat's avatar
Simon Morlat committed
25 26
static int has_type(belle_sip_object_t *obj, belle_sip_type_id_t id){
	belle_sip_object_vptr_t *vptr=obj->vptr;
27

Simon Morlat's avatar
Simon Morlat committed
28 29
	while(vptr!=NULL){
		if (vptr->id==id) return TRUE;
30
		vptr=vptr->get_parent();
Simon Morlat's avatar
Simon Morlat committed
31
	}
Simon Morlat's avatar
Simon Morlat committed
32
	return FALSE;
Simon Morlat's avatar
Simon Morlat committed
33
}
34

35
int _belle_sip_object_is_instance_of(belle_sip_object_t * obj,belle_sip_type_id_t id) {
36 37
	return has_type(obj,id);
}
38

39 40 41 42
void belle_sip_object_enable_marshal_check(int enable) {
	_belle_sip_object_marshal_check_enabled = (enable) ? TRUE : FALSE;
}

43 44 45

static belle_sip_list_t *all_objects=NULL;
static int belle_sip_leak_detector_enabled=FALSE;
46
static int belle_sip_leak_detector_inhibited=FALSE;
47 48

static void add_new_object(belle_sip_object_t *obj){
49
	if (belle_sip_leak_detector_enabled && !belle_sip_leak_detector_inhibited){
50 51 52 53 54
		all_objects=belle_sip_list_prepend(all_objects,obj);
	}
}

static void remove_free_object(belle_sip_object_t *obj){
55
	if (belle_sip_leak_detector_enabled && !belle_sip_leak_detector_inhibited){
jehan's avatar
jehan committed
56 57 58 59
		belle_sip_list_t* it;
		it=belle_sip_list_find(all_objects,obj);
		if (it)
			all_objects = belle_sip_list_delete_link(all_objects,it); /*it may fail if the leak detector was inhibitted at the time the object was created*/
60 61 62
	}
}

63 64 65 66
void belle_sip_object_inhibit_leak_detector(int yes){
	belle_sip_leak_detector_inhibited=yes ? TRUE : FALSE;
}

67 68 69 70 71
void belle_sip_object_enable_leak_detector(int enable){
	belle_sip_leak_detector_enabled=enable;
}

int belle_sip_object_get_object_count(void){
Ghislain MARY's avatar
Ghislain MARY committed
72
	return (int)belle_sip_list_size(all_objects);
73 74
}

75 76 77 78 79
void belle_sip_object_flush_active_objects(void){
	//do not free objects so that they are still detected as leaked by valgrind and such
	all_objects = belle_sip_list_free(all_objects);
}

80 81
void belle_sip_object_dump_active_objects(void){
	belle_sip_list_t *elem;
82

83
	if (all_objects){
84
		belle_sip_warning("List of leaked objects:");
85 86
		for(elem=all_objects;elem!=NULL;elem=elem->next){
			belle_sip_object_t *obj=(belle_sip_object_t*)elem->data;
87
			char* content= belle_sip_object_to_string(obj);
88
			belle_sip_warning("%s(%p) ref=%i, content [%10s...]",obj->vptr->type_name,obj,obj->ref,content);
89
			belle_sip_free(content);
90
		}
91
	}else belle_sip_warning("No objects leaked.");
92 93
}

Simon Morlat's avatar
Simon Morlat committed
94
belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr){
95
	belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(vptr->size);
96

Simon Morlat's avatar
Simon Morlat committed
97
	obj->ref=vptr->initially_unowned ? 0 : 1;
98
	obj->vptr=vptr;
99
	if (obj->ref==0){
100 101
		belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
		if (pool) belle_sip_object_pool_add(pool,obj);
102
	}
103
	add_new_object(obj);
Simon Morlat's avatar
Simon Morlat committed
104 105 106
	return obj;
}

Simon Morlat's avatar
Simon Morlat committed
107 108
int belle_sip_object_is_initially_unowned(const belle_sip_object_t *obj){
	return obj->vptr->initially_unowned;
Simon Morlat's avatar
Simon Morlat committed
109 110
}

111
belle_sip_object_t * belle_sip_object_ref(void *obj){
112
	belle_sip_object_t *o=BELLE_SIP_OBJECT(obj);
113 114
	if (o->ref==0 && o->pool){
		belle_sip_object_pool_remove(o->pool,obj);
115 116
	}
	o->ref++;
jehan's avatar
jehan committed
117
	return obj;
Simon Morlat's avatar
Simon Morlat committed
118 119
}

120 121
void belle_sip_object_unref(void *ptr){
	belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
122 123
	if (obj->ref <= -1) {
		belle_sip_error("Object [%p] freed twice or corrupted !",obj);
124
		if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name);
125
		if (obj->name) belle_sip_error("Object name might be [%s]",obj->name);
126 127 128
		belle_sip_fatal("Fatal object error encountered, aborting.");
		return;
	}
129 130 131
	if (obj->vptr->initially_unowned && obj->ref==0){
		if (obj->pool)
			belle_sip_object_pool_remove(obj->pool,obj);
132
		obj->ref=-1;
Simon Morlat's avatar
Simon Morlat committed
133
		belle_sip_object_delete(obj);
Simon Morlat's avatar
Simon Morlat committed
134 135 136
		return;
	}
	obj->ref--;
137 138
	if (obj->ref == 0){
		obj->ref = -1;
Simon Morlat's avatar
Simon Morlat committed
139
		belle_sip_object_delete(obj);
Simon Morlat's avatar
Simon Morlat committed
140 141 142
	}
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static weak_ref_t *weak_ref_new(belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){
	weak_ref_t *r=belle_sip_new(weak_ref_t);
	r->next=NULL;
	r->notify=destroy_notify;
	r->userpointer=userpointer;
	return r;
}

belle_sip_object_t *belle_sip_object_weak_ref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){
	belle_sip_object_t *o=BELLE_SIP_OBJECT(obj);
	weak_ref_t *old=o->weak_refs;
	o->weak_refs=weak_ref_new(destroy_notify,userpointer);
	o->weak_refs->next=old;
	return o;
}

void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){
	belle_sip_object_t *o=BELLE_SIP_OBJECT(obj);
	weak_ref_t *ref,*prevref=NULL,*next=NULL;
162
	int found=FALSE;
163 164 165 166 167 168 169 170

	if (o->ref==-1) return; /*too late and avoid recursions*/
	for(ref=o->weak_refs;ref!=NULL;ref=next){
		next=ref->next;
		if (ref->notify==destroy_notify && ref->userpointer==userpointer){
			if (prevref==NULL) o->weak_refs=next;
			else prevref->next=next;
			belle_sip_free(ref);
171 172
			found=TRUE;
			/*do not break or return, someone could have put twice the same weak ref on the same object*/
173 174 175 176
		}else{
			prevref=ref;
		}
	}
177
	if (!found) belle_sip_fatal("Could not find weak_ref, you're a looser.");
178 179 180 181 182 183 184 185 186 187 188 189
}

static void belle_sip_object_loose_weak_refs(belle_sip_object_t *obj){
	weak_ref_t *ref,*next;
	for(ref=obj->weak_refs;ref!=NULL;ref=next){
		next=ref->next;
		ref->notify(ref->userpointer,obj);
		belle_sip_free(ref);
	}
	obj->weak_refs=NULL;
}

Simon Morlat's avatar
Simon Morlat committed
190 191 192 193 194 195
static void _belle_sip_object_uninit(belle_sip_object_t *obj){
	if (obj->name)
		belle_sip_free(obj->name);
}

static void _belle_sip_object_clone(belle_sip_object_t *obj, const belle_sip_object_t *orig){
196
	if (orig->name!=NULL) obj->name=belle_sip_strdup(orig->name);
Simon Morlat's avatar
Simon Morlat committed
197 198
}

199
static belle_sip_error_code _belle_object_marshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
200
	return belle_sip_snprintf(buff,buff_size,offset,"{%s::%s %p}",obj->vptr->type_name,obj->name ? obj->name : "(no name)",obj);
Simon Morlat's avatar
Simon Morlat committed
201 202
}

203 204 205 206
static belle_sip_object_vptr_t *no_parent(void){
	return NULL;
}

Simon Morlat's avatar
Simon Morlat committed
207 208
belle_sip_object_vptr_t belle_sip_object_t_vptr={
	BELLE_SIP_TYPE_ID(belle_sip_object_t),
209
	sizeof(belle_sip_object_t),
Simon Morlat's avatar
Simon Morlat committed
210 211
	"belle_sip_object_t",
	FALSE,
212
	no_parent, /*no parent, it's god*/
Simon Morlat's avatar
Simon Morlat committed
213 214
	NULL,
	_belle_sip_object_uninit,
jehan's avatar
jehan committed
215
	_belle_sip_object_clone,
216 217
	_belle_object_marshal,
	BELLE_SIP_DEFAULT_BUFSIZE_HINT
Simon Morlat's avatar
Simon Morlat committed
218 219
};

220 221 222 223
belle_sip_object_vptr_t *belle_sip_object_t_vptr_get(void){
	return &belle_sip_object_t_vptr;
}

Simon Morlat's avatar
Simon Morlat committed
224
void belle_sip_object_delete(void *ptr){
225
	belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
Simon Morlat's avatar
Simon Morlat committed
226
	belle_sip_object_vptr_t *vptr;
227

228
	belle_sip_object_loose_weak_refs(obj);
229
	remove_free_object(obj);
230 231 232
	vptr=obj->vptr;
	while(vptr!=NULL){
		if (vptr->destroy) vptr->destroy(obj);
233
		vptr=vptr->get_parent();
234
	}
235
	belle_sip_object_data_clear(obj);
236
	belle_sip_free(obj);
Simon Morlat's avatar
Simon Morlat committed
237 238
}

Simon Morlat's avatar
Simon Morlat committed
239 240
static belle_sip_object_vptr_t *find_common_floor(belle_sip_object_vptr_t *vptr1, belle_sip_object_vptr_t *vptr2){
	belle_sip_object_vptr_t *it1,*it2;
241
	for (it1=vptr1;it1!=NULL;it1=it1->get_parent()){
Simon Morlat's avatar
Simon Morlat committed
242 243 244
		if (it1==vptr2)
			return vptr2;
	}
245
	for(it2=vptr2;it2!=NULL;it2=it2->get_parent()){
Simon Morlat's avatar
Simon Morlat committed
246 247 248
		if (vptr1==it2)
			return vptr1;
	}
249
	return find_common_floor(vptr1->get_parent(),vptr2);
Simon Morlat's avatar
Simon Morlat committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263
}

/*copy the content of ref object to new object, for the part they have in common in their inheritence diagram*/
void _belle_sip_object_copy(belle_sip_object_t *newobj, const belle_sip_object_t *ref){
	belle_sip_object_vptr_t *vptr;
	vptr=find_common_floor(newobj->vptr,ref->vptr);
	if (vptr==NULL){
		belle_sip_fatal("Should not happen");
	}
	while(vptr!=NULL){
		if (vptr->clone==NULL){
			belle_sip_fatal("Object of type %s cannot be cloned, it does not provide a clone() implementation.",vptr->type_name);
			return;
		}else vptr->clone(newobj,ref);
264
		vptr=vptr->get_parent();
Simon Morlat's avatar
Simon Morlat committed
265 266 267
	}
}

Simon Morlat's avatar
Simon Morlat committed
268 269
belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj){
	belle_sip_object_t *newobj;
270

271
	newobj=belle_sip_malloc0(obj->vptr->size);
jehan's avatar
jehan committed
272
	newobj->ref=obj->vptr->initially_unowned ? 0 : 1;
Simon Morlat's avatar
Simon Morlat committed
273
	newobj->vptr=obj->vptr;
Simon Morlat's avatar
Simon Morlat committed
274
	_belle_sip_object_copy(newobj,obj);
275
	if (newobj->ref==0){
276 277
		belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
		if (pool) belle_sip_object_pool_add(pool,newobj);
278
	}
279
	add_new_object(newobj);
Simon Morlat's avatar
Simon Morlat committed
280 281 282
	return newobj;
}

283 284 285
belle_sip_object_t *belle_sip_object_clone_and_ref(const belle_sip_object_t *obj) {
	return belle_sip_object_ref(belle_sip_object_clone(obj));
}
Simon Morlat's avatar
Simon Morlat committed
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

struct belle_sip_object_data{
	char* name;
	void* data;
	belle_sip_data_destroy destroy_func;
};

static int belle_sip_object_data_find(const void* a, const void* b)
{
	struct belle_sip_object_data* da = (struct belle_sip_object_data*)a;
	return strcmp(da->name, (const char*)b);
}

static void belle_sip_object_data_destroy(void* data)
{
	struct belle_sip_object_data* da = (struct belle_sip_object_data*)data;
303
	if (da->destroy_func) da->destroy_func(da->data);
304
	belle_sip_free(da->name);
305
	belle_sip_free(da);
306 307 308 309 310
}

int belle_sip_object_data_set( belle_sip_object_t *obj, const char* name, void* data, belle_sip_data_destroy destroy_func )
{
	int ret = 0;
jehan's avatar
jehan committed
311
	belle_sip_list_t*  list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name);
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL;

	if( entry == NULL){
		entry = belle_sip_malloc0(sizeof( struct belle_sip_object_data));
		obj->data_store = belle_sip_list_append(obj->data_store, entry);
	}
	else {
		// clean previous data
		if( entry->destroy_func ) entry->destroy_func(entry->data);
		belle_sip_free(entry->name);
		ret = 1;
	}

	if( entry ){
		entry->data = data;
		entry->name = belle_sip_strdup(name);
		entry->destroy_func = destroy_func;
	} else {
		ret = -1;
	}
	return ret;
}

void* belle_sip_object_data_get( belle_sip_object_t *obj, const char* name )
{
jehan's avatar
jehan committed
337
	belle_sip_list_t  *list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name);
338 339 340 341 342 343 344
	struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL;

	return entry? entry->data : NULL;
}

int belle_sip_object_data_remove( belle_sip_object_t *obj, const char* name)
{
jehan's avatar
jehan committed
345
	belle_sip_list_t  *list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name);
346 347 348 349 350 351 352 353 354 355
	struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL;
	if( entry ){
		belle_sip_free(entry->name);
		if( entry->destroy_func ) entry->destroy_func(entry->data);
		belle_sip_free(entry);
	}
	if( list_entry ) obj->data_store = belle_sip_list_remove_link(obj->data_store, list_entry);
	return !(list_entry!= NULL);
}

356
int belle_sip_object_data_exists( const belle_sip_object_t *obj, const char* name )
357 358 359 360 361 362 363
{
	return (belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name) != NULL);
}


void* belle_sip_object_data_grab( belle_sip_object_t* obj, const char* name)
{
jehan's avatar
jehan committed
364
	belle_sip_list_t  *list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name);
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
	struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL;
	void* data =NULL;

	if( entry ){
		belle_sip_free(entry->name);
		data = entry->data;
	}
	obj->data_store = belle_sip_list_remove_link(obj->data_store, list_entry);
	belle_sip_free(entry);

	return data;
}

void belle_sip_object_data_clear( belle_sip_object_t* obj )
{
	belle_sip_list_for_each(obj->data_store, belle_sip_object_data_destroy);
	obj->data_store = belle_sip_list_free(obj->data_store);
}

384
void belle_sip_object_data_clone( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func)
385 386 387 388 389
{
	belle_sip_object_data_clear(dst);
	belle_sip_object_data_merge(src, dst, clone_func);
}

390
void belle_sip_object_data_merge( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func)
391
{
jehan's avatar
jehan committed
392
	belle_sip_list_t *list = src->data_store;
393 394 395 396 397 398 399 400 401 402 403 404 405 406
	struct belle_sip_object_data* it = NULL;
	void* cloned_data = NULL;

	while( list ){
		it = list->data;
		if( it ){
			cloned_data = (clone_func)? clone_func( it->name, it->data ) : it->data;
			belle_sip_object_data_set(dst, it->name, cloned_data, it->destroy_func);
		}
		list = list->next;
	}
}


407 408 409 410 411
struct belle_sip_object_foreach_data {
	void (*apply_func)(const char*, void*, void*);
	void* userdata;
};

412
static void belle_sip_object_for_each_cb(void* data, void* pvdata)
413
{
414 415
	struct belle_sip_object_data*         it = (struct belle_sip_object_data*)data;
	struct belle_sip_object_foreach_data* fd = (struct belle_sip_object_foreach_data*)pvdata;
416

417 418 419
	if( it && fd->apply_func ){
		fd->apply_func(it->name, it->data, fd->userdata);
	}
420 421 422 423 424 425 426
}

void belle_sip_object_data_foreach( const belle_sip_object_t* obj, void (*apply_func)(const char* key, void* data, void* userdata), void* userdata)
{
	struct belle_sip_object_foreach_data fd = { apply_func, userdata };
	belle_sip_list_for_each2(obj->data_store, belle_sip_object_for_each_cb, &fd);
}
427 428


Simon Morlat's avatar
Simon Morlat committed
429
void *belle_sip_object_cast(belle_sip_object_t *obj, belle_sip_type_id_t id, const char *castname, const char *file, int fileno){
430 431 432 433 434
	if (obj!=NULL){
		if (has_type(obj,id)==0){
			belle_sip_fatal("Bad cast to %s at %s:%i",castname,file,fileno);
			return NULL;
		}
Simon Morlat's avatar
Simon Morlat committed
435 436 437
	}
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
438

439 440 441
void *belle_sip_object_get_interface_methods(belle_sip_object_t *obj, belle_sip_interface_id_t ifid){
	if (obj!=NULL){
		belle_sip_object_vptr_t *vptr;
442
		for (vptr=obj->vptr;vptr!=NULL;vptr=vptr->get_parent()){
Simon Morlat's avatar
Simon Morlat committed
443
			belle_sip_interface_desc_t **ifaces=vptr->interfaces;
444 445
			if (ifaces!=NULL){
				for(;*ifaces!=0;++ifaces){
Simon Morlat's avatar
Simon Morlat committed
446
					if ((*ifaces)->id==ifid){
447 448 449 450 451 452 453 454 455 456 457 458 459
						return *ifaces;
					}
				}
			}
		}
	}
	return NULL;
}

int belle_sip_object_implements(belle_sip_object_t *obj, belle_sip_interface_id_t id){
	return belle_sip_object_get_interface_methods(obj,id)!=NULL;
}

Simon Morlat's avatar
Simon Morlat committed
460
void *belle_sip_object_interface_cast(belle_sip_object_t *obj, belle_sip_interface_id_t ifid, const char *castname, const char *file, int fileno){
461 462 463 464 465 466 467 468
	if (obj!=NULL){
		if (belle_sip_object_get_interface_methods(obj,ifid)==0){
			belle_sip_fatal("Bad cast to interface %s at %s:%i",castname,file,fileno);
			return NULL;
		}
	}
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
469

470
void belle_sip_object_set_name(belle_sip_object_t* object,const char* name) {
Simon Morlat's avatar
Simon Morlat committed
471 472 473 474 475 476
	if (object->name) {
		belle_sip_free(object->name);
		object->name=NULL;
	}
	if (name)
		object->name=belle_sip_strdup(name);
477
}
Simon Morlat's avatar
Simon Morlat committed
478

479 480 481
const char* belle_sip_object_get_name(belle_sip_object_t* object) {
	return object->name;
}
jehan's avatar
jehan committed
482

483 484
static belle_sip_error_code checked_marshal(belle_sip_object_vptr_t *vptr, belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset){
	size_t tmp_buf_size=buff_size*2;
485
	char *p=(char*)belle_sip_malloc0(tmp_buf_size);
486 487
	size_t i;
	size_t initial_offset=*offset;
Ghislain MARY's avatar
Ghislain MARY committed
488
	belle_sip_error_code error=vptr->marshal(obj,p,buff_size,offset);
489 490 491 492 493 494
	size_t written;

	for (i=initial_offset;i<buff_size;++i){
		if (p[i]=='\0') break;
	}
	written=i-initial_offset;
495 496 497 498 499 500 501
	if (error==BELLE_SIP_OK){
		if (written!=(*offset-initial_offset) && written!=(buff_size-initial_offset-1)){ /*this is because snprintf won't allow you to write a non null character at the end of the buffer*/
			belle_sip_fatal("Object of type %s marshalled %i bytes but said it marshalled %i bytes !",
				vptr->type_name,(int)written,(int)(*offset-initial_offset));
		}
		memcpy(buff+initial_offset,p+initial_offset,*offset-initial_offset);
	}else if (error==BELLE_SIP_BUFFER_OVERFLOW){
Simon Morlat's avatar
Simon Morlat committed
502 503 504 505 506 507
		/* Case where the object aborted the marshalling because of not enough room.
		 * Should this happen, it is not allowed to write past buffer end anyway */
		if (written > buff_size){
			belle_sip_fatal("Object of type %s commited a buffer overflow by marshalling %i bytes",
				vptr->type_name,(int)(*offset-initial_offset));
		}
508
	}else{
509
		belle_sip_error("Object of type %s produced an error during marshalling: %i",
Ghislain MARY's avatar
Ghislain MARY committed
510
			vptr->type_name,error);
511
	} 
512
	belle_sip_free(p);
513
	return error;
514 515
}

516
belle_sip_error_code belle_sip_object_marshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset) {
jehan's avatar
jehan committed
517 518 519
	belle_sip_object_vptr_t *vptr=obj->vptr;
	while (vptr != NULL) {
		if (vptr->marshal != NULL) {
520 521 522 523
			if (_belle_sip_object_marshal_check_enabled == TRUE)
				return checked_marshal(vptr,obj,buff,buff_size,offset);
			else
				return vptr->marshal(obj,buff,buff_size,offset);
jehan's avatar
jehan committed
524
		} else {
525
			vptr=vptr->get_parent();
jehan's avatar
jehan committed
526 527
		}
	}
Ghislain MARY's avatar
Ghislain MARY committed
528
	return BELLE_SIP_NOT_IMPLEMENTED; /*no implementation found*/
jehan's avatar
jehan committed
529
}
Simon Morlat's avatar
Simon Morlat committed
530

531

532 533
static char * belle_sip_object_to_alloc_string(belle_sip_object_t *obj, int size_hint){
	char *buf=belle_sip_malloc(size_hint);
534
	size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
535
	belle_sip_error_code error = belle_sip_object_marshal(obj,buf,size_hint-1,&offset);
536
	obj->vptr->tostring_bufsize_hint=size_hint;
Ghislain MARY's avatar
Ghislain MARY committed
537
	if (error==BELLE_SIP_BUFFER_OVERFLOW){
538 539 540 541
		belle_sip_message("belle_sip_object_to_alloc_string(): hint buffer was too short while doing to_string() for %s, retrying", obj->vptr->type_name);
		belle_sip_free(buf);
		return belle_sip_object_to_alloc_string(obj,2*size_hint);
	}
Ghislain MARY's avatar
Ghislain MARY committed
542 543
	buf=belle_sip_realloc(buf,offset+1);
	buf[offset]='\0';
544 545
	return buf;
}
jehan's avatar
jehan committed
546

547 548 549 550 551 552
static int get_hint_size(int size){
	if (size<128)
		return 128;
	return size;
}

553 554 555 556 557 558
char* belle_sip_object_to_string(void* _obj) {
	belle_sip_object_t *obj=BELLE_SIP_OBJECT(_obj);
	if (obj->vptr->tostring_bufsize_hint!=0){
		return belle_sip_object_to_alloc_string(obj,obj->vptr->tostring_bufsize_hint);
	}else{
		char buff[BELLE_SIP_MAX_TO_STRING_SIZE];
559
		size_t offset=0;
560
		belle_sip_error_code error = belle_sip_object_marshal(obj,buff,sizeof(buff)-1,&offset);
Ghislain MARY's avatar
Ghislain MARY committed
561
		if (error==BELLE_SIP_BUFFER_OVERFLOW){
562
			belle_sip_message("belle_sip_object_to_string(): temporary buffer is too short while doing to_string() for %s, retrying", obj->vptr->type_name);
Ghislain MARY's avatar
Ghislain MARY committed
563
			return belle_sip_object_to_alloc_string(obj,get_hint_size(2*(int)offset));
564
		}
Ghislain MARY's avatar
Ghislain MARY committed
565
		buff[offset]='\0';
Ghislain MARY's avatar
Ghislain MARY committed
566
		obj->vptr->tostring_bufsize_hint=get_hint_size(2*(int)offset);
567 568
		return belle_sip_strdup(buff);
	}
jehan's avatar
jehan committed
569
}
Simon Morlat's avatar
Simon Morlat committed
570 571 572 573 574

char * _belle_sip_object_describe_type(belle_sip_object_vptr_t *vptr){
	const int maxbufsize=2048;
	char *ret=belle_sip_malloc(maxbufsize);
	belle_sip_object_vptr_t *it;
Simon Morlat's avatar
Simon Morlat committed
575
	size_t pos=0;
Simon Morlat's avatar
Simon Morlat committed
576
	belle_sip_list_t *l=NULL,*elem;
Ghislain MARY's avatar
Ghislain MARY committed
577 578
	belle_sip_snprintf(ret,maxbufsize,&pos,"Ownership:\n");
	belle_sip_snprintf(ret,maxbufsize,&pos,"\t%s is created initially %s\n",vptr->type_name,
579
				  vptr->initially_unowned ? "unowned" : "owned");
Ghislain MARY's avatar
Ghislain MARY committed
580
	belle_sip_snprintf(ret,maxbufsize,&pos,"\nInheritance diagram:\n");
581
	for(it=vptr;it!=NULL;it=it->get_parent()){
Simon Morlat's avatar
Simon Morlat committed
582 583 584 585
		l=belle_sip_list_prepend(l,it);
	}
	for(elem=l;elem!=NULL;elem=elem->next){
		it=(belle_sip_object_vptr_t*)elem->data;
Ghislain MARY's avatar
Ghislain MARY committed
586
		belle_sip_snprintf(ret,maxbufsize,&pos,"\t%s\n",it->type_name);
Simon Morlat's avatar
Simon Morlat committed
587
		if (elem->next)
Ghislain MARY's avatar
Ghislain MARY committed
588
			belle_sip_snprintf(ret,maxbufsize,&pos,"\t        |\n");
Simon Morlat's avatar
Simon Morlat committed
589 590
	}
	belle_sip_list_free(l);
Ghislain MARY's avatar
Ghislain MARY committed
591
	belle_sip_snprintf(ret,maxbufsize,&pos,"\nImplemented interfaces:\n");
592
	for(it=vptr;it!=NULL;it=it->get_parent()){
Simon Morlat's avatar
Simon Morlat committed
593 594 595
		belle_sip_interface_desc_t **desc=it->interfaces;
		if (desc!=NULL){
			for(;*desc!=NULL;desc++){
Ghislain MARY's avatar
Ghislain MARY committed
596
				belle_sip_snprintf(ret,maxbufsize,&pos,"\t* %s\n",(*desc)->ifname);
Simon Morlat's avatar
Simon Morlat committed
597 598 599 600 601 602 603 604 605 606 607
			}
		}
	}
	return ret;
}

char *belle_sip_object_describe(void *obj){
	belle_sip_object_t *o=BELLE_SIP_OBJECT(obj);
	return _belle_sip_object_describe_type(o->vptr);
}

608
#if !defined(_WIN32)
Simon Morlat's avatar
Simon Morlat committed
609

Simon Morlat's avatar
Simon Morlat committed
610 611 612 613 614 615
#include <dlfcn.h>

char *belle_sip_object_describe_type_from_name(const char *name){
	char *vptr_name;
	void *handle;
	void *symbol;
616
	belle_sip_object_get_vptr_t vptr_getter;
617

Simon Morlat's avatar
Simon Morlat committed
618 619 620 621 622
	handle=dlopen(NULL,RTLD_LAZY);
	if (handle==NULL){
		belle_sip_error("belle_sip_object_describe_type_from_name: dlopen() failed: %s",dlerror());
		return NULL;
	}
623
	vptr_name=belle_sip_strdup_printf("%s_vptr_get",name);
Simon Morlat's avatar
Simon Morlat committed
624 625 626 627 628 629 630
	symbol=dlsym(handle,vptr_name);
	belle_sip_free(vptr_name);
	dlclose(handle);
	if (symbol==NULL){
		belle_sip_error("belle_sip_object_describe_type_from_name: could not find vptr for type %s",name);
		return NULL;
	}
631 632
	vptr_getter=(belle_sip_object_get_vptr_t)symbol;
	return _belle_sip_object_describe_type(vptr_getter());
Simon Morlat's avatar
Simon Morlat committed
633
}
Simon Morlat's avatar
Simon Morlat committed
634 635 636 637 638 639 640 641 642

#else

char *belle_sip_object_describe_type_from_name(const char *name){
	return belle_sip_strdup_printf("Sorry belle_sip_object_describe_type_from_name() is not implemented on this platform.");
}

#endif

643 644 645
struct belle_sip_object_pool{
	belle_sip_object_t base;
	belle_sip_list_t *objects;
646
	unsigned long thread_id;
647 648 649 650
};

static void belle_sip_object_pool_destroy(belle_sip_object_pool_t *pool){
	belle_sip_object_pool_clean(pool);
Simon Morlat's avatar
Simon Morlat committed
651
	_belle_sip_object_pool_remove_from_stack(pool);
652 653 654 655 656 657 658
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_object_pool_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_object_pool_t,belle_sip_object_t,belle_sip_object_pool_destroy,NULL,NULL,FALSE);

belle_sip_object_pool_t *belle_sip_object_pool_new(void){
	belle_sip_object_pool_t *pool=belle_sip_object_new(belle_sip_object_pool_t);
659
	pool->thread_id=belle_sip_thread_self_id();
660 661 662 663 664 665 666 667 668 669 670 671 672
	return pool;
}

void belle_sip_object_pool_add(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){
	if (obj->pool!=NULL){
		belle_sip_fatal("It is not possible to add an object to multiple pools.");
	}
	pool->objects=belle_sip_list_prepend(pool->objects,obj);
	obj->pool_iterator=pool->objects;
	obj->pool=pool;
}

void belle_sip_object_pool_remove(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){
673
	unsigned long tid=belle_sip_thread_self_id();
674 675 676 677 678 679 680 681 682 683 684 685 686
	if (obj->pool!=pool){
		belle_sip_fatal("Attempting to remove object from an incorrect pool: obj->pool=%p, pool=%p",obj->pool,pool);
		return;
	}
	if (tid!=pool->thread_id){
		belle_sip_fatal("It is forbidden (and unsafe()) to ref()/unref() an unowned object outside of the thread that created it.");
		return;
	}
	pool->objects=belle_sip_list_delete_link(pool->objects,obj->pool_iterator);
	obj->pool_iterator=NULL;
	obj->pool=NULL;
}

687
int belle_sip_object_pool_cleanable(belle_sip_object_pool_t *pool){
688
	return pool->thread_id!=0 && belle_sip_thread_self_id()==pool->thread_id;
689 690
}

691 692
void belle_sip_object_pool_clean(belle_sip_object_pool_t *pool){
	belle_sip_list_t *elem,*next;
693

694
	if (!belle_sip_object_pool_cleanable(pool)){
695
		belle_sip_warning("Thread pool [%p] cannot be cleaned from thread [%lu] because it was created for thread [%lu]",
696
				 pool,belle_sip_thread_self_id(),(unsigned long)pool->thread_id);
697 698
		return;
	}
699

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
	for(elem=pool->objects;elem!=NULL;elem=next){
		belle_sip_object_t *obj=(belle_sip_object_t*)elem->data;
		if (obj->ref==0){
			belle_sip_message("Garbage collecting unowned object of type %s",obj->vptr->type_name);
			obj->ref=-1;
			belle_sip_object_delete(obj);
			next=elem->next;
			belle_sip_free(elem);
		}else {
			belle_sip_fatal("Object %p is in unowned list but with ref count %i, bug.",obj,obj->ref);
			next=elem->next;
		}
	}
	pool->objects=NULL;
}

716 717
static void belle_sip_object_pool_detach_from_thread(belle_sip_object_pool_t *pool){
	belle_sip_object_pool_clean(pool);
Simon Morlat's avatar
Simon Morlat committed
718
	pool->thread_id=(unsigned long)0;
719 720
}

721 722
static void cleanup_pool_stack(void *data){
	belle_sip_list_t **pool_stack=(belle_sip_list_t**)data;
723 724 725 726 727 728 729 730
	if (*pool_stack){
		/*
		 * We would expect the pool_stack to be empty when the thread terminates.
		 * Otherwise that means the management of object pool is not properly done by the application.
		 * Since the object pools might be still referenced by the application, we can't destroy them.
		 * Instead, we mark them as detached, so that when the thread that will attempt to destroy them will do it,
		 * we'll accept (since anyway these object pool are no longer needed.
		 */
731 732
		belle_sip_warning("There were still [%u] object pools for thread [%lu] while the thread exited. ",
			(unsigned int)belle_sip_list_size(*pool_stack),belle_sip_thread_self_id());
733 734
		belle_sip_list_free_with_data(*pool_stack,(void (*)(void*)) belle_sip_object_pool_detach_from_thread);
	}
735 736 737 738
	*pool_stack=NULL;
	belle_sip_free(pool_stack);
}

739
static belle_sip_list_t** get_current_pool_stack(int *first_time){
740 741 742
	static belle_sip_thread_key_t pools_key;
	static int pools_key_created=0;
	belle_sip_list_t **pool_stack;
743

744
	if (first_time) *first_time=0;
745

746 747 748 749 750 751 752 753 754 755 756
	if (!pools_key_created){
		pools_key_created=1;
		if (belle_sip_thread_key_create(&pools_key, cleanup_pool_stack)!=0){
			return NULL;
		}
	}
	pool_stack=(belle_sip_list_t**)belle_sip_thread_getspecific(pools_key);
	if (pool_stack==NULL){
		pool_stack=belle_sip_new(belle_sip_list_t*);
		*pool_stack=NULL;
		belle_sip_thread_setspecific(pools_key,pool_stack);
757
		if (first_time) *first_time=1;
758 759 760 761
	}
	return pool_stack;
}

Simon Morlat's avatar
Simon Morlat committed
762 763
static void _belle_sip_object_pool_remove_from_stack(belle_sip_object_pool_t *pool){
	belle_sip_list_t **pools=get_current_pool_stack(NULL);
764
	unsigned long tid=belle_sip_thread_self_id();
765

Simon Morlat's avatar
Simon Morlat committed
766
	if (tid!=pool->thread_id){
767
		belle_sip_fatal("It is forbidden to destroy a pool outside the thread that created it.");
Simon Morlat's avatar
Simon Morlat committed
768 769
		return;
	}
770

Simon Morlat's avatar
Simon Morlat committed
771 772 773 774 775 776 777 778 779 780 781
	if (pools==NULL) {
		belle_sip_fatal("Not possible to pop a pool.");
		return;
	}
	if (*pools==NULL){
		belle_sip_fatal("There is no current pool in stack.");
		return;
	}
	*pools=belle_sip_list_remove(*pools,pool);
}

782
belle_sip_object_pool_t * belle_sip_object_pool_push(void){
783
	belle_sip_list_t **pools=get_current_pool_stack(NULL);
784 785 786 787 788 789 790 791 792 793
	belle_sip_object_pool_t *pool;
	if (pools==NULL) {
		belle_sip_error("Not possible to create a pool.");
		return NULL;
	}
	pool=belle_sip_object_pool_new();
	*pools=belle_sip_list_prepend(*pools,pool);
	return pool;
}

Simon Morlat's avatar
Simon Morlat committed
794

795 796

belle_sip_object_pool_t *belle_sip_object_pool_get_current(void){
797 798
	int first_time;
	belle_sip_list_t **pools=get_current_pool_stack(&first_time);
799
	if (pools==NULL) return NULL;
800 801
	if (*pools==NULL ){
		if (first_time) {
802
			belle_sip_warning("There is no object pool created in thread [%lu]. "
803
			"Use belle_sip_object_pool_push() to create one. Unowned objects not unref'd will be leaked.",
804
			belle_sip_thread_self_id());
805
		}
806 807 808 809 810 811
		return NULL;
	}
	return (belle_sip_object_pool_t*)(*pools)->data;
}