xavp.c
ef79b7be
 /*
  * $Id$
  *
  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com) 
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*
  * History:
  * --------
  *  2009-05-20  created by daniel
  */
 
 
 #ifdef WITH_XAVP
 
 #include <stdio.h>
 #include <string.h>
 
 #include "mem/shm_mem.h"
 #include "dprint.h"
 #include "hashes.h"
 #include "xavp.h"
 
 /*! XAVP list head */
 static sr_xavp_t *_xavp_list_head = 0;
 /*! Pointer to XAVP current list */
 static sr_xavp_t **_xavp_list_crt = &_xavp_list_head;
 
14fb4aac
 /*! Helper functions */
 static sr_xavp_t *xavp_get_internal(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv);
 static int xavp_rm_internal(str *name, sr_xavp_t **head, int idx);
 
 
ef79b7be
 void xavp_shm_free(void *p)
 {
 	shm_free(p);
 }
 
 void xavp_shm_free_unsafe(void *p)
 {
 	shm_free_unsafe(p);
 }
 
 
 void xavp_free(sr_xavp_t *xa)
 {
 	if(xa->val.type == SR_XTYPE_DATA) {
 		if(xa->val.v.data!=NULL && xa->val.v.data->pfree!=NULL) {
 			xa->val.v.data->pfree(xa->val.v.data->p, xavp_shm_free);
 			shm_free(xa->val.v.data);
 		}
 	} else if(xa->val.type == SR_XTYPE_XAVP) {
 		xavp_destroy_list(&xa->val.v.xavp);
 	}
 	shm_free(xa);
 }
 
 void xavp_free_unsafe(sr_xavp_t *xa)
 {
 	if(xa->val.type == SR_XTYPE_DATA) {
 		if(xa->val.v.data!=NULL && xa->val.v.data->pfree!=NULL) {
 			xa->val.v.data->pfree(xa->val.v.data->p, xavp_shm_free_unsafe);
 			shm_free_unsafe(xa->val.v.data);
 		}
 	} else if(xa->val.type == SR_XTYPE_XAVP) {
 		xavp_destroy_list_unsafe(&xa->val.v.xavp);
 	}
 	shm_free_unsafe(xa);
 }
 
14fb4aac
 static sr_xavp_t *xavp_new_value(str *name, sr_xval_t *val)
ef79b7be
 {
14fb4aac
 	sr_xavp_t *avp;
ef79b7be
 	int size;
14fb4aac
 	unsigned int id;
ef79b7be
 
 	if(name==NULL || name->s==NULL || val==NULL)
 		return NULL;
14fb4aac
 	id = get_hash1_raw(name->s, name->len);
ef79b7be
 
 	size = sizeof(sr_xavp_t) + name->len + 1;
 	if(val->type == SR_XTYPE_STR)
 		size += val->v.s.len + 1;
 	avp = (sr_xavp_t*)shm_malloc(size);
 	if(avp==NULL)
 		return NULL;
 	memset(avp, 0, size);
14fb4aac
 	avp->id = id;
ef79b7be
 	avp->name.s = (char*)avp + sizeof(sr_xavp_t);
 	memcpy(avp->name.s, name->s, name->len);
 	avp->name.s[name->len] = '\0';
 	avp->name.len = name->len;
 	memcpy(&avp->val, val, sizeof(sr_xval_t));
 	if(val->type == SR_XTYPE_STR)
 	{
 		avp->val.v.s.s = avp->name.s + avp->name.len + 1;
 		memcpy(avp->val.v.s.s, val->v.s.s, val->v.s.len);
 		avp->val.v.s.s[val->v.s.len] = '\0';
 		avp->val.v.s.len = val->v.s.len;
 	}
14fb4aac
 
 	return avp;
 }
 
 sr_xavp_t *xavp_add_value(str *name, sr_xval_t *val, sr_xavp_t **list)
 {
 	sr_xavp_t *avp=0;
 
 	avp = xavp_new_value(name, val);
 	if (avp==NULL)
 		return NULL;
 
 	/* Prepend new value to the list */
ef79b7be
 	if(list) {
 		avp->next = *list;
 		*list = avp;
 	} else {
 		avp->next = *_xavp_list_crt;
 		*_xavp_list_crt = avp;
 	}
 
 	return avp;
 }
 
 sr_xavp_t *xavp_set_value(str *name, int idx, sr_xval_t *val, sr_xavp_t **list)
 {
14fb4aac
 	sr_xavp_t *avp;
 	sr_xavp_t *cur;
ef79b7be
 	sr_xavp_t *prv=0;
 
14fb4aac
 	if(val==NULL)
ef79b7be
 		return NULL;
 
14fb4aac
 	/* Find the current value */
 	cur = xavp_get_internal(name, list, idx, &prv);
 	if(cur==NULL)
ef79b7be
 		return NULL;
 
14fb4aac
 	avp = xavp_new_value(name, val);
 	if (avp==NULL)
ef79b7be
 		return NULL;
 
14fb4aac
 	/* Replace the current value with the new */
 	avp->next = cur->next;
 	if(prv)
 		prv->next = avp;
 	else if(list)
 		*list = avp;
ef79b7be
 	else
14fb4aac
 		*_xavp_list_crt = avp;
ef79b7be
 
14fb4aac
 	xavp_free(cur);
 
 	return avp;
ef79b7be
 }
 
14fb4aac
 static sr_xavp_t *xavp_get_internal(str *name, sr_xavp_t **list, int idx, sr_xavp_t **prv)
ef79b7be
 {
14fb4aac
 	sr_xavp_t *avp;
ef79b7be
 	unsigned int id;
 	int n = 0;
 
 	if(name==NULL || name->s==NULL)
 		return NULL;
 	id = get_hash1_raw(name->s, name->len);
 	
14fb4aac
 	if(list && *list)
 		avp = *list;
ef79b7be
 	else
14fb4aac
 		avp = *_xavp_list_crt;
ef79b7be
 	while(avp)
 	{
 		if(avp->id==id && avp->name.len==name->len
 				&& strncmp(avp->name.s, name->s, name->len)==0)
 		{
 			if(idx==n)
 				return avp;
 			n++;
 		}
14fb4aac
 		if(prv)
 			*prv = avp;
 		avp = avp->next;
ef79b7be
 	}
 	return NULL;
 }
 
14fb4aac
 sr_xavp_t *xavp_get(str *name, sr_xavp_t *start)
 {
4464c27f
 	return xavp_get_internal(name, (start)?&start:NULL, 0, NULL);
14fb4aac
 }
 
 sr_xavp_t *xavp_get_by_index(str *name, int idx, sr_xavp_t **start)
 {
 	return xavp_get_internal(name, start, idx, NULL);
 }
ef79b7be
 
 sr_xavp_t *xavp_get_next(sr_xavp_t *start)
 {
14fb4aac
 	sr_xavp_t *avp;
ef79b7be
 
 	if(start==NULL)
 		return NULL;
 	
 	avp = start->next;
 	while(avp)
 	{
 		if(avp->id==start->id && avp->name.len==start->name.len
 				&& strncmp(avp->name.s, start->name.s, start->name.len)==0)
 			return avp;
 		avp=avp->next;
 	}
 
 	return NULL;
 }
 
 
 int xavp_rm(sr_xavp_t *xa, sr_xavp_t **head)
 {
14fb4aac
 	sr_xavp_t *avp;
ef79b7be
 	sr_xavp_t *prv=0;
 
 	if(head!=NULL)
 		avp = *head;
 	else
 		avp=*_xavp_list_crt;
 
 	while(avp)
 	{
 		if(avp==xa)
 		{
 			if(prv)
 				prv->next=avp->next;
14fb4aac
 			else if(head!=NULL)
 				*head = avp->next;
ef79b7be
 			else
14fb4aac
 				*_xavp_list_crt = avp->next;
ef79b7be
 			xavp_free(avp);
 			return 1;
 		}
 		prv=avp; avp=avp->next;
 	}
 	return 0;
 }
 
14fb4aac
 /* Remove xavps
  * idx: <0 remove all xavps with the same name
  *      >=0 remove only the specified index xavp
  * Returns number of xavps that were deleted
  */
 static int xavp_rm_internal(str *name, sr_xavp_t **head, int idx)
ef79b7be
 {
14fb4aac
 	sr_xavp_t *avp;
 	sr_xavp_t *foo;
ef79b7be
 	sr_xavp_t *prv=0;
14fb4aac
 	unsigned int id;
ef79b7be
 	int n=0;
14fb4aac
 	int count=0;
ef79b7be
 
 	if(name==NULL || name->s==NULL)
 		return 0;
 
 	id = get_hash1_raw(name->s, name->len);
 	if(head!=NULL)
 		avp = *head;
 	else
14fb4aac
 		avp = *_xavp_list_crt;
ef79b7be
 	while(avp)
 	{
 		foo = avp;
 		avp=avp->next;
 		if(foo->id==id && foo->name.len==name->len
 				&& strncmp(foo->name.s, name->s, name->len)==0)
 		{
14fb4aac
 			if(idx<0 || idx==n)
 			{
 				if(prv!=NULL)
 					prv->next=foo->next;
 				else if(head!=NULL)
ef79b7be
 					*head = foo->next;
 				else
 					*_xavp_list_crt = foo->next;
14fb4aac
 				xavp_free(foo);
 				if(idx>=0)
 					return 1;
 				count++;
 			}
ef79b7be
 			n++;
 		} else {
 			prv = foo;
 		}
 	}
14fb4aac
 	return count;
ef79b7be
 }
 
14fb4aac
 int xavp_rm_by_name(str *name, int all, sr_xavp_t **head)
ef79b7be
 {
14fb4aac
 	return xavp_rm_internal(name, head, -1*all);
 }
ef79b7be
 
14fb4aac
 int xavp_rm_by_index(str *name, int idx, sr_xavp_t **head)
 {
 	if (idx<0)
ef79b7be
 		return 0;
14fb4aac
 	return xavp_rm_internal(name, head, idx);
ef79b7be
 }
 
 
 int xavp_count(str *name, sr_xavp_t **start)
 {
14fb4aac
 	sr_xavp_t *avp;
ef79b7be
 	unsigned int id;
 	int n = 0;
 
 	if(name==NULL || name->s==NULL)
 		return -1;
 	id = get_hash1_raw(name->s, name->len);
 	
 	if(start)
 		avp = *start;
 	else
 		avp=*_xavp_list_crt;
 	while(avp)
 	{
 		if(avp->id==id && avp->name.len==name->len
 				&& strncmp(avp->name.s, name->s, name->len)==0)
 		{
 			n++;
 		}
 		avp=avp->next;
 	}
 
 	return n;
 }
 
 void xavp_destroy_list_unsafe(sr_xavp_t **head)
 {
 	sr_xavp_t *avp, *foo;
 
 	avp = *head;
 	while(avp)
 	{
 		foo = avp;
 		avp = avp->next;
 		xavp_free_unsafe(foo);
 	}
 	*head = 0;
 }
 
 
 void xavp_destroy_list(sr_xavp_t **head)
 {
 	sr_xavp_t *avp, *foo;
 
 	LM_DBG("destroying xavp list %p\n", *head);
 	avp = *head;
 	while(avp)
 	{
 		foo = avp;
 		avp = avp->next;
 		xavp_free(foo);
 	}
 	*head = 0;
 }
 
 
 void xavp_reset_list(void)
 {
 	assert(_xavp_list_crt!=0 );
 	
 	if (_xavp_list_crt!=&_xavp_list_head)
 		_xavp_list_crt=&_xavp_list_head;
 	xavp_destroy_list(_xavp_list_crt);
 }
 
 
 sr_xavp_t **xavp_set_list(sr_xavp_t **head)
 {
 	sr_xavp_t **avp;
 	
 	assert(_xavp_list_crt!=0);
 
 	avp = _xavp_list_crt;
 	_xavp_list_crt = head;
 	return avp;
 }
 
 sr_xavp_t **xavp_get_crt_list(void)
 {
 	assert(_xavp_list_crt!=0);
 	return _xavp_list_crt;
 }
 
395e0dae
 void xavp_print_list_content(sr_xavp_t **head, int level)
ef79b7be
 {
 	sr_xavp_t *avp=0;
395e0dae
 	sr_xavp_t *start=0;
ef79b7be
 
 	if(head!=NULL)
395e0dae
 		start = *head;
ef79b7be
 	else
395e0dae
 		start=*_xavp_list_crt;
024e7483
 	LM_INFO("+++++ start XAVP list: %p (level=%d)\n", start, level);
395e0dae
 	avp = start;
ef79b7be
 	while(avp)
 	{
024e7483
 		LM_INFO("     *** XAVP name: %s\n", avp->name.s);
 		LM_INFO("     XAVP id: %u\n", avp->id);
 		LM_INFO("     XAVP value type: %d\n", avp->val.type);
ef79b7be
 		switch(avp->val.type) {
 			case SR_XTYPE_NULL:
024e7483
 				LM_INFO("     XAVP value: <null>\n");
ef79b7be
 			break;
 			case SR_XTYPE_INT:
024e7483
 				LM_INFO("     XAVP value: %d\n", avp->val.v.i);
ef79b7be
 			break;
 			case SR_XTYPE_STR:
024e7483
 				LM_INFO("     XAVP value: %s\n", avp->val.v.s.s);
ef79b7be
 			break;
 			case SR_XTYPE_TIME:
e91db504
 				LM_INFO("     XAVP value: %lu\n",
 						(long unsigned int)avp->val.v.t);
ef79b7be
 			break;
 			case SR_XTYPE_LONG:
024e7483
 				LM_INFO("     XAVP value: %ld\n", avp->val.v.l);
ef79b7be
 			break;
 			case SR_XTYPE_LLONG:
024e7483
 				LM_INFO("     XAVP value: %lld\n", avp->val.v.ll);
ef79b7be
 			break;
 			case SR_XTYPE_XAVP:
024e7483
 				LM_INFO("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
395e0dae
 				xavp_print_list_content(&avp->val.v.xavp, level+1);
ef79b7be
 			break;
 			case SR_XTYPE_DATA:
024e7483
 				LM_INFO("     XAVP value: <data:%p>\n", avp->val.v.data);
ef79b7be
 			break;
 		}
 		avp = avp->next;
 	}
024e7483
 	LM_INFO("----- end XAVP list: %p (level=%d)\n", start, level);
ef79b7be
 }
 
395e0dae
 void xavp_print_list(sr_xavp_t **head)
 {
 	xavp_print_list_content(head, 0);
 }
ef79b7be
 #endif