Initial commit

Change-Id: I6a4444e3c193dae437cd7929f4c39aba7b749efa
diff --git a/extensions/app_sip/libapp_sip.c b/extensions/app_sip/libapp_sip.c
new file mode 100644
index 0000000..6442ff4
--- /dev/null
+++ b/extensions/app_sip/libapp_sip.c
@@ -0,0 +1,1078 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Alexandre Westfahl <awestfahl@freediameter.net>						 *
+*													 *
+* Copyright (c) 2010, Alexandre Westfahl, Teraoka Laboratory (Keio University), and the WIDE Project. 	 *		
+*													 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the Teraoka Laboratory nor the 							 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of Teraoka Laboratory 						 *
+*   													 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+//#include <mysql.h>
+#include "app_sip.h"
+
+MYSQL *conn;
+
+void clear_digest(uint8_t * digest, char * readable_digest, int digestlength)
+{
+	int i=0;
+	for(i=0;i<digestlength * 2;i++)
+		sprintf(&readable_digest[2 * i], "%2.2hhx", digest[i]);
+	readable_digest[2 * digestlength]='\0';
+	
+	return;
+}
+
+// You must create a table like this "char  clearDigest[DIGEST_LEN*2+1];"
+void calc_md5(char *clearDigest, char * data)
+{
+	gcry_md_hd_t md5;
+	uint8_t * binDigest=NULL;
+	
+	CHECK_MALLOC_DO(binDigest=malloc(DIGEST_LEN),return);
+	
+	gcry_md_open(&md5,GCRY_MD_MD5, 0); 
+	gcry_md_write(md5, (char *)data, sizeof(data));
+	memcpy(binDigest, gcry_md_read(md5,  GCRY_MD_MD5),gcry_md_get_algo_dlen(GCRY_MD_MD5));
+	gcry_md_close(md5);
+	
+	clear_digest(binDigest, clearDigest, DIGEST_LEN);
+	free(binDigest);
+	return;
+}
+
+
+/* Search a given AVP model in an AVP (extracted from libfreediameter/message.c ) */
+int fd_avp_search_avp ( struct avp * groupedavp, struct dict_object * what, struct avp ** avp )
+{
+	struct avp * nextavp;
+	struct avp_hdr * nextavphdr;
+	struct dict_avp_data 	dictdata;
+	
+	
+	TRACE_ENTRY("%p %p %p", groupedavp, what, avp);
+	
+	CHECK_FCT(  fd_dict_getval(what, &dictdata)  );
+	
+	// Loop only in the group AVP 
+	CHECK_FCT(  fd_msg_browse(groupedavp, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL)  );
+	CHECK_FCT( fd_msg_avp_hdr( nextavp, &nextavphdr )  );
+	
+	while (nextavphdr) {
+		
+		if ( (nextavphdr->avp_code   == dictdata.avp_code) && (nextavphdr->avp_vendor == dictdata.avp_vendor) ) // always 0 if no Vendor flag
+		{
+			break;
+		}
+		
+		// Otherwise move to next AVP in the grouped AVP 
+		CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) );
+		
+		if(nextavp!=NULL)
+		{
+			CHECK_FCT( fd_msg_avp_hdr( nextavp, &nextavphdr )  );
+		}
+		else
+			nextavphdr=NULL;
+	}
+	if (avp)
+		*avp = nextavp;
+	
+	if (avp && nextavp) {
+		struct dictionary * dict;
+		CHECK_FCT( fd_dict_getdict( what, &dict) );
+		CHECK_FCT_DO( fd_msg_parse_dict( nextavp, dict, NULL ),  );
+	}
+	
+	if (avp || nextavp)
+		return 0;
+	else
+		return ENOENT;
+}
+struct avp_hdr *walk_digest(struct avp *avp, int avp_code)
+{
+	struct avp_hdr *temphdr=NULL;
+	CHECK_FCT_DO(fd_msg_browse ( avp, MSG_BRW_WALK, &avp, NULL),return NULL);
+	
+	while(avp!=NULL)
+	{
+		
+		CHECK_FCT_DO( fd_msg_avp_hdr( avp,&temphdr ),return NULL);
+
+		if(temphdr->avp_code==avp_code)
+		{
+			//We found the AVP so we set avp to NULL to exit the loop
+			avp=NULL;
+			return temphdr;
+			
+		}
+		else if(temphdr->avp_code==380)//SIP-Authorization AVP
+		{
+			//We didn't found the AVP but we finished browsing the Authentication AVP
+			avp=NULL;
+			temphdr=NULL;
+			
+			return temphdr;
+		}
+		else
+		{
+			CHECK_FCT_DO(fd_msg_browse ( avp, MSG_BRW_WALK, &avp, NULL),return NULL);
+			temphdr=NULL;
+			
+		}
+	}
+	
+	return temphdr;
+}
+
+int start_mysql_connection()
+{
+	conn = mysql_init(NULL);
+	
+	mysql_options(conn, MYSQL_OPT_RECONNECT, "true");
+	
+	if (!mysql_real_connect(conn, as_conf->mysql_server,as_conf->mysql_login, as_conf->mysql_password, as_conf->mysql_database, as_conf->mysql_port, NULL, 0)) 
+	{//TODO: display error from mysql
+		TRACE_DEBUG(INFO,"Unable to connect to database (%s) with login:%s",as_conf->mysql_database,as_conf->mysql_login);
+		return 1;
+	}
+	return 0;
+	
+}
+
+
+void request_mysql(char *query)
+{
+	//We check if the connection is still up
+	mysql_ping(conn);
+	
+	if (mysql_query(conn, query)) 
+	{
+		TRACE_DEBUG(INFO,"Query %s failed", query);
+		
+	}
+	
+}
+
+void close_mysql_connection()
+{
+	mysql_close(conn);
+	
+}
+
+//If password is null, we just verify this user exist
+//We don't need the password length because it is a table'
+int get_password(const unsigned char *username, const size_t usernamelen, char *password)
+{
+	CHECK_PARAMS(username && usernamelen);
+	
+	int not_found=2;
+	size_t querylen, usernamepurelen;
+	char *query, *username_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			//We copy username in query
+			querylen=SQL_GETPASSWORD_LEN + usernamepurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_GETPASSWORD, username_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				if(password!=NULL)
+					password[0]='\0';
+				free(query);
+				return 2;
+			}
+			
+			
+			
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				if(strlen(row[0])>0)
+				{
+					if(password!=NULL)
+						strcpy(password,row[0]);
+					
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+		break;
+	}
+	return not_found;
+}
+
+int check_sipaor(const unsigned char  *username, const size_t usernamelen, const char * sip_aor,const size_t sipaorlen)
+{
+	CHECK_PARAMS(username && usernamelen && sip_aor && sipaorlen);
+	
+	int not_found=2;
+	size_t querylen, usernamepurelen;
+	char *query, *username_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+	
+			//We get the list of AOR owned by this user
+			querylen=SQL_GETSIPAOR_LEN + usernamepurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_GETSIPAOR, username_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			//We make the query
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				free(query);
+				return 2;
+			}
+			
+			
+			not_found=1;
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				if(strncmp((const char *)sip_aor,row[0],sipaorlen)==0)
+				{
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+		break;
+	}
+	return not_found;
+}
+
+int get_diameter_uri(const unsigned char *sip_aor, const size_t sipaorlen, char ** diameter_uri, size_t *diameterurilen)
+{
+	CHECK_PARAMS(sip_aor && sipaorlen);
+
+	size_t querylen, sipaorpurelen;
+	char *query, *sipaor_pure;
+	int not_found=2;
+
+
+
+
+	//a sip aor must begin by "sip:" or "sips:" so it must at least be longer than 4 chars
+	if(sipaorlen<5)
+		return 2;
+
+	//NOTE: each method has to purify sip_aor itself. You must remove quotes or special chars for security
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+
+			querylen=SQL_GETDIAMURI_LEN + sipaorlen;
+
+			
+			//We allocate the double size of SIP-URI because at worst it can be all quotes
+			CHECK_MALLOC(sipaor_pure=malloc(sipaorlen*2+1));
+			//We purify SIP-URI not to have forbidden characters
+			sipaorpurelen=mysql_real_escape_string(conn, sipaor_pure, (const char *)sip_aor, sipaorlen);
+			
+			
+			query = malloc(querylen+sipaorpurelen+ 2);
+			snprintf(query, querylen+1, SQL_GETDIAMURI, sipaor_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				//We couldn't make the request
+				diameter_uri=NULL;
+				return 2;
+			}
+			
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				*diameterurilen=strlen(row[0]);
+				if(*diameterurilen>0)
+				{
+					CHECK_MALLOC(*diameter_uri=malloc(*diameterurilen+1));
+					strcpy(*diameter_uri,row[0]);
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+			free(sipaor_pure);
+		break;
+      
+    default:
+      
+      //We must never go here, if so, we must stop diameter_sip
+      diameter_uri=NULL;
+      return 2;
+      
+      break;
+  }
+  
+  //0 if it was found
+  return not_found;
+  
+}
+
+
+int exist_username(const unsigned char *sip_aor, const size_t sipaorlen)
+{
+	CHECK_PARAMS(sip_aor && sipaorlen);
+	
+	size_t querylen, sipaorpurelen;
+	char *query, *sipaor_pure;
+	int not_found=1;
+	
+	//a sip aor must begin by "sip:" or "sips:" so it must at least be longer than 4 chars
+	if(sipaorlen<5)
+		return 2;
+	
+	//NOTE: each method has to purify sip_aor itself. You must remove quotes or special chars for security
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			
+			querylen=SQL_GETUSERNAME_LEN + sipaorlen;
+			
+			
+			//We allocate the double size of SIP-URI because at worst it can be all quotes
+			CHECK_MALLOC(sipaor_pure=malloc(sipaorlen*2+1));
+			//We purify SIP-URI not to have forbidden characters
+			sipaorpurelen=mysql_real_escape_string(conn, sipaor_pure, (const char *)sip_aor, sipaorlen);
+			
+			
+			query = malloc(querylen+sipaorpurelen+ 2);
+			snprintf(query, querylen+1, SQL_GETUSERNAME, sipaor_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				//We couldn't make the request
+				return 2;
+			}
+			
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				if(strlen(row[0])>0)
+				{
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+			free(sipaor_pure);
+			break;
+			
+		default:
+			
+			//We must never go here, if so, we must stop diameter_sip
+			TRACE_DEBUG(INFO,"FATAL ERROR: the datasource is unknown, please check your config file!");
+			return 2;
+			
+			break;
+	}
+	
+	//0 if it was found
+	return not_found;
+	
+}
+
+//We check if this user can go in the given network
+int allow_roaming(const unsigned char  *username, const size_t usernamelen, const char * network,const size_t networklen)
+{
+	CHECK_PARAMS(username && usernamelen && network && networklen);
+	
+	int not_found=2;
+	size_t querylen, usernamepurelen;
+	char *query, *username_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			//We get the list of AOR owned by this user
+			querylen=SQL_GETUSERNET_LEN + usernamepurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_GETUSERNET, username_pure);
+			
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			
+			//We make the query
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				free(query);
+				return 2;
+			}
+			
+			
+			not_found=1;
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				if(strncmp((const char *)network,row[0],networklen)==0)
+				{
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+			break;
+	}
+	return not_found;
+}
+
+//SIP-Server-Capabilities for the SIP-AOR
+int get_sipserver_cap(const unsigned char *sip_aor, const size_t sipaorlen, struct avp **capabilities)
+{
+	CHECK_PARAMS(sip_aor && sipaorlen && capabilities);
+	
+	size_t querylen, sipaorpurelen;
+	char *query, *sipaor_pure;
+	int not_found=2;
+	union avp_value value;
+	struct avp *avp;
+	
+	//a sip aor must begin by "sip:" or "sips:" so it must at least be longer than 4 chars
+	if(sipaorlen<5)
+		return 2;
+	
+	//NOTE: each method has to purify sip_aor itself. You must remove quotes or special chars for security
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			
+			querylen=SQL_GETSIPSERCAP_LEN + sipaorlen;
+			
+			
+			//We allocate the double size of SIP-URI because at worst it can be all quotes
+			CHECK_MALLOC(sipaor_pure=malloc(sipaorlen*2+1));
+			//We purify SIP-URI not to have forbidden characters
+			sipaorpurelen=mysql_real_escape_string(conn, sipaor_pure, (const char *)sip_aor, sipaorlen);
+			
+			
+			query = malloc(querylen+sipaorpurelen+ 2);
+			snprintf(query, querylen+1, SQL_GETSIPSERCAP, sipaor_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				//We couldn't make the request
+				return 2;
+			}
+			not_found=1;
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				if(atoi(row[0])==1)
+				{//mandatory
+					CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Mandatory_Capability, 0, &avp ) );
+					value.i32=(uint32_t)atoi(row[1]);
+					CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
+					CHECK_FCT( fd_msg_avp_add ( *capabilities, MSG_BRW_LAST_CHILD, avp) );
+					
+				}
+				else
+				{//optional
+					CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Optional_Capability, 0, &avp ) );
+					value.i32=(uint32_t)atoi(row[1]);
+					CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
+					CHECK_FCT( fd_msg_avp_add ( *capabilities, MSG_BRW_LAST_CHILD, avp) );
+				}
+				not_found=0;
+			}
+			
+			mysql_free_result(res);
+			free(query);
+			free(sipaor_pure);
+			break;
+			
+		default:
+			
+			//We must never go here, if so, we must stop diameter_sip
+			TRACE_DEBUG(INFO,"FATAL ERROR: the datasource is unknown, please check your config file!");
+			return 2;
+			
+			break;
+	}
+	
+	//0 if it was found
+	return not_found;
+	
+}
+
+
+//We retrieve datatype
+int add_user_datatype(const unsigned char  *sip_aor, const size_t sipaorlen,struct msg *message)
+{
+	CHECK_PARAMS(sip_aor && sipaorlen && message );
+	
+	size_t querylen, sipaorpurelen;
+	char *query, *sipaor_pure;
+	int not_found=2;
+	union avp_value value;
+	struct avp *avp, *rootavp;
+	unsigned long *length;
+	
+	//a sip aor must begin by "sip:" or "sips:" so it must at least be longer than 4 chars
+	if(sipaorlen<5)
+		return 2;
+	
+	//NOTE: each method has to purify sip_aor itself. You must remove quotes or special chars for security
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			
+			querylen=SQL_GETSIPDATA_LEN + sipaorlen;
+			
+			
+			//We allocate the double size of SIP-URI because at worst it can be all quotes
+			CHECK_MALLOC(sipaor_pure=malloc(sipaorlen*2+1));
+			//We purify SIP-URI not to have forbidden characters
+			sipaorpurelen=mysql_real_escape_string(conn, sipaor_pure, (const char *)sip_aor, sipaorlen);
+			
+			
+			query = malloc(querylen+sipaorpurelen+ 2);
+			snprintf(query, querylen+1, SQL_GETSIPDATA, sipaor_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				//We couldn't make the request
+				return 2;
+			}
+			not_found=1;
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				length=mysql_fetch_lengths(res);
+				
+				if(strlen(row[0])>1)
+				{
+					CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_User_Data, 0, &rootavp ) );
+					
+					CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_User_Data_Type, 0, &avp ) );
+					CHECK_MALLOC(value.os.data=malloc(length[0]*sizeof(unsigned char)));
+					strncpy((char *)value.os.data,(char *)row[0],length[0]);
+					value.os.len=(size_t)length[0];
+					CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
+					CHECK_FCT( fd_msg_avp_add ( rootavp, MSG_BRW_LAST_CHILD, avp) );
+					
+					
+					
+					CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_User_Data_Contents, 0, &avp ) );
+					CHECK_MALLOC(value.os.data=malloc(length[1]*sizeof(unsigned char)));
+					memcpy(value.os.data,row[1],length[1]);
+					value.os.len=(size_t)length[1];
+					CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
+					CHECK_FCT( fd_msg_avp_add ( rootavp, MSG_BRW_LAST_CHILD, avp) );
+					
+					//We add SIP_User_Data to message
+					CHECK_FCT( fd_msg_avp_add ( message, MSG_BRW_LAST_CHILD, rootavp) );
+					not_found=0;
+				}
+				
+			}
+			
+			mysql_free_result(res);
+			free(query);
+			free(sipaor_pure);
+			break;
+			
+			default:
+				
+				//We must never go here, if so, we must stop diameter_sip
+				TRACE_DEBUG(INFO,"FATAL ERROR: the datasource is unknown, please check your config file!");
+				return 2;
+				
+				break;
+	}
+	
+	//0 if it was found
+	return not_found;
+	
+	
+	
+}
+
+int set_pending_flag(const unsigned char  *username, const size_t usernamelen)
+{
+	CHECK_PARAMS(username && usernamelen);
+	
+	
+	size_t querylen, usernamepurelen;
+	char *query, *username_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			
+			
+			//We clear the flag "authentication pending"
+			querylen=SQL_SETFLAG_LEN + usernamepurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_SETFLAG, username_pure);
+			
+			if (mysql_query(conn, query)) 
+			{
+				TRACE_DEBUG(INFO,"Query %s failed", query);
+				free(query);
+				return 2;
+			}
+			
+			free(query);
+			break;
+	}	
+	return 0;
+}
+int clear_pending_flag(const unsigned char  *username, const size_t usernamelen)
+{
+	CHECK_PARAMS(username && usernamelen);
+	
+	
+	size_t querylen, usernamepurelen;
+	char *query, *username_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			
+			
+			//We clear the flag "authentication pending"
+			querylen=SQL_CLEARFLAG_LEN + usernamepurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_CLEARFLAG, username_pure);
+			
+			if (mysql_query(conn, query)) 
+			{
+				TRACE_DEBUG(INFO,"Query %s failed", query);
+				free(query);
+				return 2;
+			}
+			
+			free(query);
+		break;
+	}	
+	return 0;
+}
+
+
+
+int set_sipserver_uri(const unsigned char  *username, const size_t usernamelen, const unsigned char *sipserver_uri,const size_t sipserverurilen)
+{
+	CHECK_PARAMS(username && usernamelen && sipserver_uri && sipserverurilen);
+	
+	
+	size_t querylen, usernamepurelen, sipserveruripurelen;
+	char *query, *username_pure, *sipserveruri_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			//We allocate the double size of username because at worst it can be all quotes
+			sipserveruri_pure=malloc(sipserverurilen*2+1);
+			//We purify username not to have forbidden characters
+			sipserveruripurelen=mysql_real_escape_string(conn, sipserveruri_pure, (const char *)sipserver_uri, sipserverurilen);
+			
+			//We clear the flag "authentication pending"
+			querylen=SQL_SETSIPURI_LEN + usernamepurelen + sipserveruripurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_SETSIPURI, sipserveruri_pure,username_pure);
+			
+			if (mysql_query(conn, query)) 
+			{
+				TRACE_DEBUG(INFO,"Query %s failed", query);
+				free(query);
+				return 2;
+			}
+			
+			free(query);
+			break;
+	}	
+	return 0;
+}
+int remove_sipserver_uri(const unsigned char *sipserver_uri,const size_t sipserverurilen)
+{
+	CHECK_PARAMS(sipserver_uri && sipserverurilen);
+	
+
+	size_t querylen, sipserveruripurelen;
+	char *query, *sipserveruri_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			sipserveruri_pure=malloc(sipserverurilen*2+1);
+			//We purify username not to have forbidden characters
+			sipserveruripurelen=mysql_real_escape_string(conn, sipserveruri_pure, (const char *)sipserver_uri, sipserverurilen);
+			
+			//We clear the flag "authentication pending"
+			querylen=SQL_RMSIPURI_LEN + sipserveruripurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_RMSIPURI, sipserveruri_pure);
+			
+			if (mysql_query(conn, query)) 
+			{
+				TRACE_DEBUG(INFO,"Query %s failed", query);
+				free(query);
+				return 2;
+			}
+			
+			free(query);
+			break;
+	}	
+	return 0;
+}
+int set_real_sipserver_uri(const unsigned char  *username, const size_t usernamelen, const unsigned char *sipserver_uri,const size_t sipserverurilen)
+{
+	CHECK_PARAMS(username && usernamelen && sipserver_uri && sipserverurilen);
+	
+	
+	size_t querylen, usernamepurelen, sipserveruripurelen;
+	char *query, *username_pure, *sipserveruri_pure;
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			//We allocate the double size of username because at worst it can be all quotes
+			username_pure=malloc(usernamelen*2+1);
+			//We purify username not to have forbidden characters
+			usernamepurelen=mysql_real_escape_string(conn, username_pure, (const char *)username, usernamelen);
+			
+			//We allocate the double size of username because at worst it can be all quotes
+			sipserveruri_pure=malloc(sipserverurilen*2+1);
+			//We purify username not to have forbidden characters
+			sipserveruripurelen=mysql_real_escape_string(conn, sipserveruri_pure, (const char *)sipserver_uri, sipserverurilen);
+			
+			//We clear the flag "authentication pending"
+			querylen=SQL_SETREALSIPURI_LEN + usernamepurelen + sipserveruripurelen;
+			query = malloc(querylen+2);
+			snprintf(query, querylen+1, SQL_SETREALSIPURI, sipserveruri_pure,username_pure);
+			
+			if (mysql_query(conn, query)) 
+			{
+				TRACE_DEBUG(INFO,"Query %s failed", query);
+				free(query);
+				return 2;
+			}
+			
+			free(query);
+			break;
+	}	
+	return 0;
+}
+
+int get_sipserver_uri(const unsigned char *sip_aor, const size_t sipaorlen, unsigned char ** sipserver_uri, size_t *sipserverurilen)
+{
+	CHECK_PARAMS(sip_aor && sipaorlen && sipserver_uri && sipserverurilen );
+	
+	size_t querylen, sipaorpurelen;
+	char *query, *sipaor_pure;
+	int not_found=2;
+	
+	
+	
+	
+	//a sip aor must begin by "sip:" or "sips:" so it must at least be longer than 4 chars
+	if(sipaorlen<5)
+		return 2;
+	
+	//NOTE: each method has to purify sip_aor itself. You must remove quotes or special chars for security
+	
+	switch(as_conf->datasource)
+	{
+		//MySQL
+		case ASMYSQL:
+			
+			querylen=SQL_GETSIPSERURI_LEN + sipaorlen;
+			
+			//We allocate the double size of SIP-URI because at worst it can be all quotes
+			CHECK_MALLOC(sipaor_pure=malloc(sipaorlen*2+1));
+			//We purify SIP-URI not to have forbidden characters
+			sipaorpurelen=mysql_real_escape_string(conn, sipaor_pure, (const char *)sip_aor, sipaorlen);
+			
+			
+			query = malloc(querylen+sipaorpurelen+ 2);
+			snprintf(query, querylen+1, SQL_GETSIPSERURI, sipaor_pure);
+			
+			MYSQL_RES *res;
+			MYSQL_ROW row;
+			
+			//We make the query	
+			request_mysql(query);
+			res=mysql_use_result(conn);
+			if(res==NULL)
+			{
+				//We couldn't make the request
+				sipserver_uri=NULL;
+				return 2;
+			}
+			
+			not_found=1;
+			while ((row = mysql_fetch_row(res)) != NULL)
+			{
+				*sipserverurilen=strlen(row[0]);
+				if(*sipserverurilen>4)
+				{
+					CHECK_MALLOC(*sipserver_uri=malloc(*sipserverurilen+1));
+					strcpy((char *)*sipserver_uri,row[0]);
+					not_found=0;
+					break;
+				}
+			}
+			mysql_free_result(res);
+			free(query);
+			free(sipaor_pure);
+			break;
+			
+		default:
+			
+			//We must never go here, if so, we must stop diameter_sip
+			TRACE_DEBUG(INFO,"FATAL ERROR: the datasource is unknown, please check your config file!");
+			sipserver_uri=NULL;
+			return 2;
+			
+			break;
+	}
+	
+	//0 if it was found
+	return not_found;
+	
+}
+
+
+int count_avp(struct msg * message, int code, int vendor)
+{
+	CHECK_PARAMS(message);
+	
+	struct avp_hdr *temphdr;
+	struct avp *avp;
+	int counter=0;
+	
+	CHECK_FCT(fd_msg_browse (message, MSG_BRW_WALK, &avp, NULL));
+	
+	while(avp!=NULL)
+	{
+		
+		CHECK_FCT( fd_msg_avp_hdr( avp,&temphdr ));
+		
+		if(temphdr->avp_code==code && temphdr->avp_vendor==vendor)
+		{
+			counter++;
+		}
+		
+		CHECK_FCT(fd_msg_browse (avp, MSG_BRW_WALK, &avp, NULL));
+	}
+	return counter;
+}
+/* 
+void nonce_add_element(char * nonce)
+{
+	noncechain *newelt=malloc(sizeof(noncechain));
+	
+	newelt->nonce=nonce;
+	
+	newelt->timestamp=(int)time(NULL);
+	newelt->next=NULL;
+	
+	if(listnonce==NULL)
+	{
+		listnonce=newelt;
+	}
+	else
+	{
+		noncechain* temp=listnonce;
+		
+		while(temp->next != NULL)
+		{
+			if(temp->timestamp < ((int)time(NULL)-300))
+			{
+				listnonce=temp->next;
+				free(temp);
+				temp=listnonce;
+			}
+			temp = temp->next;
+		}
+		temp->next = newelt;
+	}
+	
+}
+void nonce_del_element(char * nonce)
+{
+	if(listnonce!=NULL)
+	{
+		noncechain *temp=listnonce, *tempbefore=NULL;
+		
+		if(listnonce->next==NULL && strcmp(listnonce->nonce,nonce)==0)
+		{
+			free(listnonce);
+			listnonce=NULL;
+			return;
+		}
+		while(temp->next != NULL)
+		{
+			if(strcmp(temp->nonce,nonce)==0)
+			{
+				if(tempbefore==NULL)
+				{
+					listnonce=temp->next;
+					free(temp);
+					return;
+				}
+				tempbefore->next=temp->next;
+				free(temp);
+				break;
+			}
+			tempbefore=temp;
+			temp = temp->next;
+		}
+		
+	}
+	
+}
+int nonce_check_element(char * nonce)
+{
+	if(listnonce==NULL)
+	{
+		//Not found
+		return 0;
+	}
+	else
+	{
+		noncechain* temp=listnonce;
+		
+		while(temp->next != NULL)
+		{
+			if(strcmp(temp->nonce,nonce)==0)
+				return 1;
+			else
+				temp = temp->next;
+		}
+	}
+	return 0;
+}
+
+void nonce_deletelistnonce()
+{
+	if(listnonce !=NULL)
+	{
+		noncechain* temp=listnonce;
+	
+		while(listnonce->next != NULL)
+		{
+			temp = listnonce->next;
+		
+			free(listnonce);
+		
+			listnonce=temp;
+		}
+		free(listnonce);
+	}
+}
+*/