belle_sip_object.c 6.44 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
	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 <http://www.gnu.org/licenses/>.
*/

#include "belle_sip_internal.h"

Simon Morlat's avatar
Simon Morlat committed
21 22 23 24 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;
	
	while(vptr!=NULL){
		if (vptr->id==id) return TRUE;
		vptr=vptr->parent;
Simon Morlat's avatar
Simon Morlat committed
27
	}
Simon Morlat's avatar
Simon Morlat committed
28
	return FALSE;
Simon Morlat's avatar
Simon Morlat committed
29
}
30 31

int belle_sip_object_is_instance_of(belle_sip_object_t * obj,belle_sip_type_id_t id) {
32 33
	return has_type(obj,id);
}
34

Simon Morlat's avatar
Simon Morlat committed
35
belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr, int initially_unowed){
Simon Morlat's avatar
Simon Morlat committed
36 37
	belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(objsize);
	obj->ref=initially_unowed ? 0 : 1;
38
	obj->vptr=vptr;
Simon Morlat's avatar
Simon Morlat committed
39
	obj->size=objsize;
Simon Morlat's avatar
Simon Morlat committed
40 41 42 43 44 45 46
	return obj;
}

int belle_sip_object_is_unowed(const belle_sip_object_t *obj){
	return obj->ref==0;
}

47 48
belle_sip_object_t * belle_sip_object_ref(void *obj){
	BELLE_SIP_OBJECT(obj)->ref++;
jehan's avatar
jehan committed
49
	return obj;
Simon Morlat's avatar
Simon Morlat committed
50 51
}

52 53
void belle_sip_object_unref(void *ptr){
	belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
Simon Morlat's avatar
Simon Morlat committed
54
	if (obj->ref==0){
55
		/*might hide a double unref belle_sip_warning("Destroying unowed object");*/
Simon Morlat's avatar
Simon Morlat committed
56
		belle_sip_object_delete(obj);
Simon Morlat's avatar
Simon Morlat committed
57 58 59 60
		return;
	}
	obj->ref--;
	if (obj->ref==0){
Simon Morlat's avatar
Simon Morlat committed
61
		belle_sip_object_delete(obj);
Simon Morlat's avatar
Simon Morlat committed
62 63 64
	}
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
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;

	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);
			return;
		}else{
			prevref=ref;
		}
	}
	belle_sip_fatal("Could not find weak_ref, you're a looser.");
}

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
110 111 112 113 114 115 116 117 118 119 120 121 122 123
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){
	if (orig->name!=NULL) obj->name=belle_sip_strdup(obj->name);
}

belle_sip_object_vptr_t belle_sip_object_t_vptr={
	BELLE_SIP_TYPE_ID(belle_sip_object_t),
	NULL, /*no parent, it's god*/
	NULL,
	_belle_sip_object_uninit,
jehan's avatar
jehan committed
124 125
	_belle_sip_object_clone,
	NULL
Simon Morlat's avatar
Simon Morlat committed
126 127 128
};

void belle_sip_object_delete(void *ptr){
129
	belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
Simon Morlat's avatar
Simon Morlat committed
130
	belle_sip_object_vptr_t *vptr;
131
	
Simon Morlat's avatar
Simon Morlat committed
132 133 134
	if (obj->ref!=0){
		belle_sip_error("Destroying referenced object !");
	}
135 136 137 138 139 140 141 142
	obj->ref=-1;
	belle_sip_object_loose_weak_refs(obj);
	vptr=obj->vptr;
	while(vptr!=NULL){
		if (vptr->destroy) vptr->destroy(obj);
		vptr=vptr->parent;
	}
	belle_sip_free(obj);
Simon Morlat's avatar
Simon Morlat committed
143 144
}

Simon Morlat's avatar
Simon Morlat committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158
belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj){
	belle_sip_object_t *newobj;
	belle_sip_object_vptr_t *vptr;
	
	newobj=belle_sip_malloc0(obj->size);
	newobj->ref=1;
	newobj->vptr=obj->vptr;
	
	vptr=obj->vptr;
	while(vptr!=NULL){
		if (vptr->clone==NULL){
			belle_sip_fatal("Object of type %i cannot be cloned, it does not provide a clone() implementation.",vptr->id);
			return NULL;
		}else vptr->clone(newobj,obj);
jehan's avatar
jehan committed
159
		vptr=vptr->parent;
Simon Morlat's avatar
Simon Morlat committed
160 161 162 163
	}
	return newobj;
}

Simon Morlat's avatar
Simon Morlat committed
164
void *belle_sip_object_cast(belle_sip_object_t *obj, belle_sip_type_id_t id, const char *castname, const char *file, int fileno){
165 166 167 168 169
	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
170 171 172
	}
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
173

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
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;
		for (vptr=obj->vptr;vptr!=NULL;vptr=vptr->parent){
			belle_sip_interface_id_t **ifaces=vptr->interfaces;
			if (ifaces!=NULL){
				for(;*ifaces!=0;++ifaces){
					if (**ifaces==ifid){
						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;
}

void *belle_sip_object_cast_to_interface(belle_sip_object_t *obj, belle_sip_interface_id_t ifid, const char *castname, const char *file, int fileno){
	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
204

205
void belle_sip_object_set_name(belle_sip_object_t* object,const char* name) {
Simon Morlat's avatar
Simon Morlat committed
206 207 208 209 210 211
	if (object->name) {
		belle_sip_free(object->name);
		object->name=NULL;
	}
	if (name)
		object->name=belle_sip_strdup(name);
212
}
Simon Morlat's avatar
Simon Morlat committed
213

214 215 216
const char* belle_sip_object_get_name(belle_sip_object_t* object) {
	return object->name;
}
jehan's avatar
jehan committed
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

int belle_sip_object_marshal(belle_sip_object_t* obj, char* buff,unsigned int offset,size_t buff_size) {
	belle_sip_object_vptr_t *vptr=obj->vptr;
	while (vptr != NULL) {
		if (vptr->marshal != NULL) {
			return vptr->marshal(obj,buff,offset,buff_size);
		} else {
			vptr=vptr->parent;
		}
	}
	return -1; /*no implementation found*/
}
char* belle_sip_object_to_string(belle_sip_object_t* obj) {
	char buff[2048]; /*to be optimized*/
	int size = belle_sip_object_marshal(obj,buff,0,sizeof(buff));
	buff[size]='\0';
	return strdup(buff);

}