Browse Source

- mergin with ser cvs head

git-svn-id: https://openser.svn.sourceforge.net/svnroot/openser/trunk@29 689a6050-402a-0410-94f2-e92a70836424
Daniel-Constantin Mierla 20 năm trước cách đây
mục cha
commit
857b95ea53
7 tập tin đã thay đổi với 542 bổ sung11 xóa
  1. 11 5
      lib/srdb1/db.c
  2. 15 4
      lib/srdb1/db.h
  3. 3 2
      lib/srdb1/db_cap.h
  4. 269 0
      lib/srdb1/db_id.c
  5. 57 0
      lib/srdb1/db_id.h
  6. 115 0
      lib/srdb1/db_pool.c
  7. 72 0
      lib/srdb1/db_pool.h

+ 11 - 5
lib/srdb1/db.c

@@ -2,7 +2,7 @@
  * $Id$
  * $Id$
  *
  *
  * Copyright (C) 2001-2003 FhG Fokus
  * Copyright (C) 2001-2003 FhG Fokus
- *
+ * 
  * This file is part of openser, a free SIP server.
  * This file is part of openser, a free SIP server.
  *
  *
  * openser is free software; you can redistribute it and/or modify
  * openser is free software; you can redistribute it and/or modify
@@ -18,11 +18,12 @@
  * You should have received a copy of the GNU General Public License 
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * History:
- * --------
- *  2004-06-06  bind_dbmod takes dbf as parameter (andrei)
  */
  */
+ /*
+  * History:
+  * --------
+  *  2004-06-06  bind_dbmod takes dbf as parameter (andrei)
+  */
 
 
 
 
 #include "../dprint.h"
 #include "../dprint.h"
@@ -129,6 +130,11 @@ int bind_dbmod(char* mod, db_func_t* mydbf)
 		dbf.cap |= DB_CAP_UPDATE;
 		dbf.cap |= DB_CAP_UPDATE;
 	}
 	}
 
 
+	dbf.replace = (db_replace_f)find_mod_export(tmp, "db_replace", 2, 0);
+	if (dbf.replace) {
+		dbf.cap |= DB_CAP_REPLACE;
+	}
+
 	*mydbf=dbf; /* copy */
 	*mydbf=dbf; /* copy */
 	return 0;
 	return 0;
 
 

+ 15 - 4
lib/srdb1/db.h

@@ -3,14 +3,19 @@
  *
  *
  * Copyright (C) 2001-2003 FhG Fokus
  * Copyright (C) 2001-2003 FhG Fokus
  *
  *
- * This file is part of openser, a free SIP server.
+ * This file is part of ser, a free SIP server.
  *
  *
- * openser is free software; you can redistribute it and/or modify
+ * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  * (at your option) any later version
  *
  *
- * openser is distributed in the hope that it will be useful,
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  * GNU General Public License for more details.
@@ -18,7 +23,8 @@
  * You should have received a copy of the GNU General Public License 
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ */
+/*
  * History:
  * History:
  * --------
  * --------
  *  2004-06-06  removed db_* macros and global dbf (andrei)
  *  2004-06-06  removed db_* macros and global dbf (andrei)
@@ -126,6 +132,10 @@ typedef int (*db_delete_f) (db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _
 typedef int (*db_update_f) (db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
 typedef int (*db_update_f) (db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
 			    db_key_t* _uk, db_val_t* _uv, int _n, int _un);
 			    db_key_t* _uk, db_val_t* _uv, int _n, int _un);
 
 
+/*
+ * Insert a row and replace if one already 
+ */
+typedef int (*db_replace_f) (db_con_t* handle, db_key_t* keys, db_val_t* vals, int n);
 
 
 
 
 typedef struct db_func {
 typedef struct db_func {
@@ -139,6 +149,7 @@ typedef struct db_func {
 	db_insert_f      insert;       /* Insert into table */
 	db_insert_f      insert;       /* Insert into table */
 	db_delete_f      delete;       /* Delete from table */ 
 	db_delete_f      delete;       /* Delete from table */ 
 	db_update_f      update;       /* Update table */
 	db_update_f      update;       /* Update table */
+	db_replace_f     replace;      /* Replace row in a table */
 } db_func_t;
 } db_func_t;
 
 
 
 

+ 3 - 2
lib/srdb1/db_cap.h

@@ -32,12 +32,13 @@ typedef enum db_cap {
 	DB_CAP_RAW_QUERY = 1 << 1,  /* Database driver can perform raw queries */
 	DB_CAP_RAW_QUERY = 1 << 1,  /* Database driver can perform raw queries */
 	DB_CAP_INSERT =    1 << 2,  /* Database driver can insert data into database */
 	DB_CAP_INSERT =    1 << 2,  /* Database driver can insert data into database */
 	DB_CAP_DELETE =    1 << 3,  /* Database driver can delete data from database */
 	DB_CAP_DELETE =    1 << 3,  /* Database driver can delete data from database */
-	DB_CAP_UPDATE =    1 << 4   /* Database driver can update data in the database */
+	DB_CAP_UPDATE =    1 << 4,  /* Database driver can update data in the database */
+	DB_CAP_REPLACE =   1 << 5,  /* Replace (also known as INSERT OR UPDATE) support */
 } db_cap_t;
 } db_cap_t;
 
 
 
 
 /*
 /*
- * All database capabilities except raw_query which should be checked
+ * All database capabilities except raw_query and replace which should be checked
  * separately when needed
  * separately when needed
  */
  */
 #define DB_CAP_ALL (DB_CAP_QUERY | DB_CAP_INSERT | DB_CAP_DELETE | DB_CAP_UPDATE)
 #define DB_CAP_ALL (DB_CAP_QUERY | DB_CAP_INSERT | DB_CAP_DELETE | DB_CAP_UPDATE)

+ 269 - 0
lib/srdb1/db_id.c

@@ -0,0 +1,269 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2001-2005 iptel.org
+ *
+ * This file is part of openser, a free SIP server.
+ *
+ * openser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser 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, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "db_id.h"
+#include "../dprint.h"
+#include "../mem/mem.h"
+#include "../ut.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Duplicate a string
+ */
+static int dupl_string(char** dst, const char* begin, const char* end)
+{
+	if (*dst) pkg_free(*dst);
+
+	*dst = pkg_malloc(end - begin + 1);
+	if ((*dst) == NULL) {
+		return -1;
+	}
+
+	memcpy(*dst, begin, end - begin);
+	(*dst)[end - begin] = '\0';
+	return 0;
+}
+
+
+/*
+ * Parse a database URL of form 
+ * scheme://[username[:password]@]hostname[:port]/database
+ *
+ * Returns 0 if parsing was successful and -1 otherwise
+ */
+static int parse_db_url(struct db_id* id, const char* url)
+{
+#define SHORTEST_DB_URL "s://a/b"
+#define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
+
+	enum state {
+		ST_SCHEME,     /* Scheme part */
+		ST_SLASH1,     /* First slash */
+		ST_SLASH2,     /* Second slash */
+		ST_USER_HOST,  /* Username or hostname */
+		ST_PASS_PORT,  /* Password or port part */
+		ST_HOST,       /* Hostname part */
+		ST_PORT,       /* Port part */
+		ST_DB          /* Database part */
+	};
+
+	enum state st;
+	int len, i;
+	const char* begin;
+	char* prev_token;
+
+	prev_token = 0;
+
+	if (!id || !url) {
+		goto err;
+	}
+	
+	len = strlen(url);
+	if (len < SHORTEST_DB_URL_LEN) {
+		goto err;
+	}
+	
+	     /* Initialize all attributes to 0 */
+	memset(id, 0, sizeof(struct db_id));
+	st = ST_SCHEME;
+	begin = url;
+
+	for(i = 0; i < len; i++) {
+		switch(st) {
+		case ST_SCHEME:
+			switch(url[i]) {
+			case ':':
+				st = ST_SLASH1;
+				if (dupl_string(&id->scheme, begin, url + i) < 0) goto err;
+				break;
+			}
+			break;
+
+		case ST_SLASH1:
+			switch(url[i]) {
+			case '/':
+				st = ST_SLASH2;
+				break;
+
+			default:
+				goto err;
+			}
+			break;
+
+		case ST_SLASH2:
+			switch(url[i]) {
+			case '/':
+				st = ST_USER_HOST;
+				begin = url + i + 1;
+				break;
+				
+			default:
+				goto err;
+			}
+			break;
+
+		case ST_USER_HOST:
+			switch(url[i]) {
+			case '@':
+				st = ST_HOST;
+				if (dupl_string(&id->username, begin, url + i) < 0) goto err;
+				begin = url + i + 1;
+				break;
+
+			case ':':
+				st = ST_PASS_PORT;
+				if (dupl_string(&prev_token, begin, url + i) < 0) goto err;
+				begin = url + i + 1;
+				break;
+
+			case '/':
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
+				return 0;
+			}
+			break;
+
+		case ST_PASS_PORT:
+			switch(url[i]) {
+			case '@':
+				st = ST_HOST;
+				id->username = prev_token;
+				if (dupl_string(&id->password, begin, url + i) < 0) goto err;
+				begin = url + i + 1;
+				break;
+
+			case '/':
+				id->host = prev_token;
+				id->port = str2s(begin, url + i - begin, 0);
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
+				return 0;
+			}
+			break;
+
+		case ST_HOST:
+			switch(url[i]) {
+			case ':':
+				st = ST_PORT;
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
+				begin = url + i + 1;
+				break;
+
+			case '/':
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
+				return 0;
+			}
+			break;
+
+		case ST_PORT:
+			switch(url[i]) {
+			case '/':
+				id->port = str2s(begin, url + i - begin, 0);
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
+				return 0;
+			}
+			break;
+			
+		case ST_DB:
+			break;
+		}
+	}
+
+	if (st != ST_DB) goto err;
+	return 0;
+
+ err:
+	if (id->scheme) pkg_free(id->scheme);
+	if (id->username) pkg_free(id->username);
+	if (id->password) pkg_free(id->password);
+	if (id->host) pkg_free(id->host);
+	if (id->database) pkg_free(id->database);
+	if (prev_token) pkg_free(prev_token);
+	return -1;
+}
+
+
+/*
+ * Create a new connection identifier
+ */
+struct db_id* new_db_id(const char* url)
+{
+	struct db_id* ptr;
+
+	if (!url) {
+		LOG(L_ERR, "new_db_id: Invalid parameter\n");
+		return 0;
+	}
+
+	ptr = (struct db_id*)pkg_malloc(sizeof(struct db_id));
+	if (!ptr) {
+		LOG(L_ERR, "new_db_id: No memory left\n");
+		goto err;
+	}
+	memset(ptr, 0, sizeof(struct db_id));
+
+	if (parse_db_url(ptr, url) < 0) {
+		LOG(L_ERR, "new_db_id: Error while parsing database URL: %s\n", url);
+		goto err;
+	}
+
+	return ptr;
+
+ err:
+	if (ptr) pkg_free(ptr);
+	return 0;
+}
+
+
+/*
+ * Compare two connection identifiers
+ */
+unsigned char cmp_db_id(struct db_id* id1, struct db_id* id2)
+{
+	if (!id1 || !id2) return 0;
+	if (id1->port != id2->port) return 0;
+
+	if (strcmp(id1->scheme, id2->scheme)) return 0;
+	if (strcmp(id1->username, id2->username)) return 0;
+	if (strcmp(id1->password, id2->password)) return 0;
+	if (strcasecmp(id1->host, id2->host)) return 0;
+	if (strcmp(id1->database, id2->database)) return 0;
+	return 1;
+}
+
+
+/*
+ * Free a connection identifier
+ */
+void free_db_id(struct db_id* id)
+{
+	if (!id) return;
+
+	if (id->scheme) pkg_free(id->scheme);
+	if (id->username) pkg_free(id->username);
+	if (id->password) pkg_free(id->password);
+	if (id->host) pkg_free(id->host);
+	if (id->database) pkg_free(id->database);
+	pkg_free(id);
+}

+ 57 - 0
lib/srdb1/db_id.h

@@ -0,0 +1,57 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2001-2005 iptel.org
+ * 
+ * This file is part of openser, a free SIP server.
+ *
+ * openser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser 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, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DB_ID_H
+#define _DB_ID_H
+
+#include "../str.h"
+
+
+struct db_id {
+	char* scheme;        /* URL scheme */
+	char* username;      /* Username, case sensitive */
+	char* password;      /* Password, case sensitive */
+	char* host;          /* Host or IP, case insensitive */
+	unsigned short port; /* Port number */
+	char* database;      /* Database, case sensitive */
+};
+
+
+/*
+ * Create a new connection identifier
+ */
+struct db_id* new_db_id(const char* url);
+
+
+/*
+ * Compare two connection identifiers
+ */
+unsigned char cmp_db_id(struct db_id* id1, struct db_id* id2);
+
+
+/*
+ * Free a connection identifier
+ */
+void free_db_id(struct db_id* id);
+
+
+#endif /* _DB_ID_H */

+ 115 - 0
lib/srdb1/db_pool.c

@@ -0,0 +1,115 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2001-2005 iptel.org
+ *
+ * This file is part of openser, a free SIP server.
+ *
+ * openser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser 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, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "../dprint.h"
+#include "db_pool.h"
+
+
+/* The head of the pool */
+static struct pool_con* db_pool = 0;
+
+
+/*
+ * Search the pool for a connection with
+ * the identifier equal to id, NULL is returned
+ * when no connection is found
+ */
+struct pool_con* pool_get(struct db_id* id)
+{
+	struct pool_con* ptr;
+
+	if (!id) {
+		LOG(L_ERR, "pool_get: Invalid parameter value\n");
+		return 0;
+	}
+
+	ptr = db_pool;
+	while (ptr) {
+		if (cmp_db_id(id, ptr->id)) {
+			ptr->ref++;
+			return ptr;
+		}
+		ptr = ptr->next;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Insert a new connection into the pool
+ */
+void pool_insert(struct pool_con* con)
+{
+	if (!con) return;
+
+	con->next = db_pool;
+	db_pool = con;
+}
+
+
+/*
+ * Release connection from the pool, the function
+ * would return 1 when if the connection is not
+ * referenced anymore and thus can be closed and
+ * deleted by the backend. The function returns
+ * 0 if the connection should still be kept open
+ * because some other module is still using it.
+ * The function returns -1 if the connection is
+ * not in the pool.
+ */
+int pool_remove(struct pool_con* con)
+{
+	struct pool_con* ptr;
+
+	if (!con) return -2;
+
+	if (con->ref > 1) {
+		     /* There are still other users, just
+		      * decrease the reference count and return
+		      */
+		DBG("pool_remove: Connection still kept in the pool\n");
+		con->ref--;
+		return 0;
+	}
+
+	DBG("pool_remove: Removing connection from the pool\n");
+
+	if (db_pool == con) {
+		db_pool = db_pool->next;
+	} else {
+		ptr = db_pool;
+		while(ptr) {
+			if (ptr->next == con) break;
+			ptr = ptr->next;
+		}
+		if (!ptr) {
+			LOG(L_ERR, "pool_remove: Weird, connection not found in the pool\n");
+			return -1;
+		} else {
+			     /* Remove the connection from the pool */
+			ptr->next = con->next;
+		}
+	}
+
+	return 1;
+}

+ 72 - 0
lib/srdb1/db_pool.h

@@ -0,0 +1,72 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2001-2005 iptel.org
+ *
+ * This file is part of openser, a free SIP server.
+ *
+ * openser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser 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, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _DB_POOL_H
+#define _DB_POOL_H
+
+#include "db_id.h"
+#include "db_con.h"
+
+
+/*
+ * This is a stub that contains all attributes
+ * that pool members must have, it is not really
+ * used, real connection structures are created
+ * by database backends. All such structures (
+ * created by the backends) must have these
+ * attributes.
+ */
+struct pool_con {
+	struct db_id* id;        /* Connection identifier */
+	unsigned int ref;        /* Reference count */
+	struct pool_con* next;   /* Next element in the pool */
+};
+
+
+/*
+ * Search the pool for a connection with
+ * the identifier equal to id, NULL is returned
+ * when no connection is found
+ */
+struct pool_con* pool_get(struct db_id* id);
+
+
+/*
+ * Insert a new connection into the pool
+ */
+void pool_insert(struct pool_con* con);
+
+
+/*
+ * Release connection from the pool, the function
+ * would return 1 when if the connection is not
+ * referenced anymore and thus can be closed and
+ * deleted by the backend. The function returns
+ * 0 if the connection should still be kept open
+ * because some other module is still using it.
+ * The function returns -1 if the connection is
+ * not in the pool.
+ */
+int pool_remove(struct pool_con* con);
+
+
+#endif /* _POOL_H */