Browse code

- 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 authored on 16/06/2005 12:07:08
Showing 7 changed files
... ...
@@ -2,7 +2,7 @@
2 2
  * $Id$
3 3
  *
4 4
  * Copyright (C) 2001-2003 FhG Fokus
5
- *
5
+ * 
6 6
  * This file is part of openser, a free SIP server.
7 7
  *
8 8
  * openser is free software; you can redistribute it and/or modify
... ...
@@ -18,11 +18,12 @@
18 18
  * You should have received a copy of the GNU General Public License 
19 19
  * along with this program; if not, write to the Free Software 
20 20
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- *
22
- * History:
23
- * --------
24
- *  2004-06-06  bind_dbmod takes dbf as parameter (andrei)
25 21
  */
22
+ /*
23
+  * History:
24
+  * --------
25
+  *  2004-06-06  bind_dbmod takes dbf as parameter (andrei)
26
+  */
26 27
 
27 28
 
28 29
 #include "../dprint.h"
... ...
@@ -129,6 +130,11 @@ int bind_dbmod(char* mod, db_func_t* mydbf)
129 130
 		dbf.cap |= DB_CAP_UPDATE;
130 131
 	}
131 132
 
133
+	dbf.replace = (db_replace_f)find_mod_export(tmp, "db_replace", 2, 0);
134
+	if (dbf.replace) {
135
+		dbf.cap |= DB_CAP_REPLACE;
136
+	}
137
+
132 138
 	*mydbf=dbf; /* copy */
133 139
 	return 0;
134 140
 
... ...
@@ -3,14 +3,19 @@
3 3
  *
4 4
  * Copyright (C) 2001-2003 FhG Fokus
5 5
  *
6
- * This file is part of openser, a free SIP server.
6
+ * This file is part of ser, a free SIP server.
7 7
  *
8
- * openser is free software; you can redistribute it and/or modify
8
+ * ser is free software; you can redistribute it and/or modify
9 9
  * it under the terms of the GNU General Public License as published by
10 10
  * the Free Software Foundation; either version 2 of the License, or
11 11
  * (at your option) any later version
12 12
  *
13
- * openser is distributed in the hope that it will be useful,
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
14 19
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 20
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 21
  * GNU General Public License for more details.
... ...
@@ -18,7 +23,8 @@
18 23
  * You should have received a copy of the GNU General Public License 
19 24
  * along with this program; if not, write to the Free Software 
20 25
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- *
26
+ */
27
+/*
22 28
  * History:
23 29
  * --------
24 30
  *  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* _
126 132
 typedef int (*db_update_f) (db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
127 133
 			    db_key_t* _uk, db_val_t* _uv, int _n, int _un);
128 134
 
135
+/*
136
+ * Insert a row and replace if one already 
137
+ */
138
+typedef int (*db_replace_f) (db_con_t* handle, db_key_t* keys, db_val_t* vals, int n);
129 139
 
130 140
 
131 141
 typedef struct db_func {
... ...
@@ -139,6 +149,7 @@ typedef struct db_func {
139 149
 	db_insert_f      insert;       /* Insert into table */
140 150
 	db_delete_f      delete;       /* Delete from table */ 
141 151
 	db_update_f      update;       /* Update table */
152
+	db_replace_f     replace;      /* Replace row in a table */
142 153
 } db_func_t;
143 154
 
144 155
 
... ...
@@ -32,12 +32,13 @@ typedef enum db_cap {
32 32
 	DB_CAP_RAW_QUERY = 1 << 1,  /* Database driver can perform raw queries */
33 33
 	DB_CAP_INSERT =    1 << 2,  /* Database driver can insert data into database */
34 34
 	DB_CAP_DELETE =    1 << 3,  /* Database driver can delete data from database */
35
-	DB_CAP_UPDATE =    1 << 4   /* Database driver can update data in the database */
35
+	DB_CAP_UPDATE =    1 << 4,  /* Database driver can update data in the database */
36
+	DB_CAP_REPLACE =   1 << 5,  /* Replace (also known as INSERT OR UPDATE) support */
36 37
 } db_cap_t;
37 38
 
38 39
 
39 40
 /*
40
- * All database capabilities except raw_query which should be checked
41
+ * All database capabilities except raw_query and replace which should be checked
41 42
  * separately when needed
42 43
  */
43 44
 #define DB_CAP_ALL (DB_CAP_QUERY | DB_CAP_INSERT | DB_CAP_DELETE | DB_CAP_UPDATE)
44 45
new file mode 100644
... ...
@@ -0,0 +1,269 @@
1
+/* 
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2001-2005 iptel.org
5
+ *
6
+ * This file is part of openser, a free SIP server.
7
+ *
8
+ * openser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * openser is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+#include "db_id.h"
24
+#include "../dprint.h"
25
+#include "../mem/mem.h"
26
+#include "../ut.h"
27
+#include <stdlib.h>
28
+#include <string.h>
29
+
30
+
31
+/*
32
+ * Duplicate a string
33
+ */
34
+static int dupl_string(char** dst, const char* begin, const char* end)
35
+{
36
+	if (*dst) pkg_free(*dst);
37
+
38
+	*dst = pkg_malloc(end - begin + 1);
39
+	if ((*dst) == NULL) {
40
+		return -1;
41
+	}
42
+
43
+	memcpy(*dst, begin, end - begin);
44
+	(*dst)[end - begin] = '\0';
45
+	return 0;
46
+}
47
+
48
+
49
+/*
50
+ * Parse a database URL of form 
51
+ * scheme://[username[:password]@]hostname[:port]/database
52
+ *
53
+ * Returns 0 if parsing was successful and -1 otherwise
54
+ */
55
+static int parse_db_url(struct db_id* id, const char* url)
56
+{
57
+#define SHORTEST_DB_URL "s://a/b"
58
+#define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
59
+
60
+	enum state {
61
+		ST_SCHEME,     /* Scheme part */
62
+		ST_SLASH1,     /* First slash */
63
+		ST_SLASH2,     /* Second slash */
64
+		ST_USER_HOST,  /* Username or hostname */
65
+		ST_PASS_PORT,  /* Password or port part */
66
+		ST_HOST,       /* Hostname part */
67
+		ST_PORT,       /* Port part */
68
+		ST_DB          /* Database part */
69
+	};
70
+
71
+	enum state st;
72
+	int len, i;
73
+	const char* begin;
74
+	char* prev_token;
75
+
76
+	prev_token = 0;
77
+
78
+	if (!id || !url) {
79
+		goto err;
80
+	}
81
+	
82
+	len = strlen(url);
83
+	if (len < SHORTEST_DB_URL_LEN) {
84
+		goto err;
85
+	}
86
+	
87
+	     /* Initialize all attributes to 0 */
88
+	memset(id, 0, sizeof(struct db_id));
89
+	st = ST_SCHEME;
90
+	begin = url;
91
+
92
+	for(i = 0; i < len; i++) {
93
+		switch(st) {
94
+		case ST_SCHEME:
95
+			switch(url[i]) {
96
+			case ':':
97
+				st = ST_SLASH1;
98
+				if (dupl_string(&id->scheme, begin, url + i) < 0) goto err;
99
+				break;
100
+			}
101
+			break;
102
+
103
+		case ST_SLASH1:
104
+			switch(url[i]) {
105
+			case '/':
106
+				st = ST_SLASH2;
107
+				break;
108
+
109
+			default:
110
+				goto err;
111
+			}
112
+			break;
113
+
114
+		case ST_SLASH2:
115
+			switch(url[i]) {
116
+			case '/':
117
+				st = ST_USER_HOST;
118
+				begin = url + i + 1;
119
+				break;
120
+				
121
+			default:
122
+				goto err;
123
+			}
124
+			break;
125
+
126
+		case ST_USER_HOST:
127
+			switch(url[i]) {
128
+			case '@':
129
+				st = ST_HOST;
130
+				if (dupl_string(&id->username, begin, url + i) < 0) goto err;
131
+				begin = url + i + 1;
132
+				break;
133
+
134
+			case ':':
135
+				st = ST_PASS_PORT;
136
+				if (dupl_string(&prev_token, begin, url + i) < 0) goto err;
137
+				begin = url + i + 1;
138
+				break;
139
+
140
+			case '/':
141
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
142
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
143
+				return 0;
144
+			}
145
+			break;
146
+
147
+		case ST_PASS_PORT:
148
+			switch(url[i]) {
149
+			case '@':
150
+				st = ST_HOST;
151
+				id->username = prev_token;
152
+				if (dupl_string(&id->password, begin, url + i) < 0) goto err;
153
+				begin = url + i + 1;
154
+				break;
155
+
156
+			case '/':
157
+				id->host = prev_token;
158
+				id->port = str2s(begin, url + i - begin, 0);
159
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
160
+				return 0;
161
+			}
162
+			break;
163
+
164
+		case ST_HOST:
165
+			switch(url[i]) {
166
+			case ':':
167
+				st = ST_PORT;
168
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
169
+				begin = url + i + 1;
170
+				break;
171
+
172
+			case '/':
173
+				if (dupl_string(&id->host, begin, url + i) < 0) goto err;
174
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
175
+				return 0;
176
+			}
177
+			break;
178
+
179
+		case ST_PORT:
180
+			switch(url[i]) {
181
+			case '/':
182
+				id->port = str2s(begin, url + i - begin, 0);
183
+				if (dupl_string(&id->database, url + i + 1, url + len) < 0) goto err;
184
+				return 0;
185
+			}
186
+			break;
187
+			
188
+		case ST_DB:
189
+			break;
190
+		}
191
+	}
192
+
193
+	if (st != ST_DB) goto err;
194
+	return 0;
195
+
196
+ err:
197
+	if (id->scheme) pkg_free(id->scheme);
198
+	if (id->username) pkg_free(id->username);
199
+	if (id->password) pkg_free(id->password);
200
+	if (id->host) pkg_free(id->host);
201
+	if (id->database) pkg_free(id->database);
202
+	if (prev_token) pkg_free(prev_token);
203
+	return -1;
204
+}
205
+
206
+
207
+/*
208
+ * Create a new connection identifier
209
+ */
210
+struct db_id* new_db_id(const char* url)
211
+{
212
+	struct db_id* ptr;
213
+
214
+	if (!url) {
215
+		LOG(L_ERR, "new_db_id: Invalid parameter\n");
216
+		return 0;
217
+	}
218
+
219
+	ptr = (struct db_id*)pkg_malloc(sizeof(struct db_id));
220
+	if (!ptr) {
221
+		LOG(L_ERR, "new_db_id: No memory left\n");
222
+		goto err;
223
+	}
224
+	memset(ptr, 0, sizeof(struct db_id));
225
+
226
+	if (parse_db_url(ptr, url) < 0) {
227
+		LOG(L_ERR, "new_db_id: Error while parsing database URL: %s\n", url);
228
+		goto err;
229
+	}
230
+
231
+	return ptr;
232
+
233
+ err:
234
+	if (ptr) pkg_free(ptr);
235
+	return 0;
236
+}
237
+
238
+
239
+/*
240
+ * Compare two connection identifiers
241
+ */
242
+unsigned char cmp_db_id(struct db_id* id1, struct db_id* id2)
243
+{
244
+	if (!id1 || !id2) return 0;
245
+	if (id1->port != id2->port) return 0;
246
+
247
+	if (strcmp(id1->scheme, id2->scheme)) return 0;
248
+	if (strcmp(id1->username, id2->username)) return 0;
249
+	if (strcmp(id1->password, id2->password)) return 0;
250
+	if (strcasecmp(id1->host, id2->host)) return 0;
251
+	if (strcmp(id1->database, id2->database)) return 0;
252
+	return 1;
253
+}
254
+
255
+
256
+/*
257
+ * Free a connection identifier
258
+ */
259
+void free_db_id(struct db_id* id)
260
+{
261
+	if (!id) return;
262
+
263
+	if (id->scheme) pkg_free(id->scheme);
264
+	if (id->username) pkg_free(id->username);
265
+	if (id->password) pkg_free(id->password);
266
+	if (id->host) pkg_free(id->host);
267
+	if (id->database) pkg_free(id->database);
268
+	pkg_free(id);
269
+}
0 270
new file mode 100644
... ...
@@ -0,0 +1,57 @@
1
+/* 
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2001-2005 iptel.org
5
+ * 
6
+ * This file is part of openser, a free SIP server.
7
+ *
8
+ * openser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * openser is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+#ifndef _DB_ID_H
24
+#define _DB_ID_H
25
+
26
+#include "../str.h"
27
+
28
+
29
+struct db_id {
30
+	char* scheme;        /* URL scheme */
31
+	char* username;      /* Username, case sensitive */
32
+	char* password;      /* Password, case sensitive */
33
+	char* host;          /* Host or IP, case insensitive */
34
+	unsigned short port; /* Port number */
35
+	char* database;      /* Database, case sensitive */
36
+};
37
+
38
+
39
+/*
40
+ * Create a new connection identifier
41
+ */
42
+struct db_id* new_db_id(const char* url);
43
+
44
+
45
+/*
46
+ * Compare two connection identifiers
47
+ */
48
+unsigned char cmp_db_id(struct db_id* id1, struct db_id* id2);
49
+
50
+
51
+/*
52
+ * Free a connection identifier
53
+ */
54
+void free_db_id(struct db_id* id);
55
+
56
+
57
+#endif /* _DB_ID_H */
0 58
new file mode 100644
... ...
@@ -0,0 +1,115 @@
1
+/* 
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2001-2005 iptel.org
5
+ *
6
+ * This file is part of openser, a free SIP server.
7
+ *
8
+ * openser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * openser is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+#include "../dprint.h"
24
+#include "db_pool.h"
25
+
26
+
27
+/* The head of the pool */
28
+static struct pool_con* db_pool = 0;
29
+
30
+
31
+/*
32
+ * Search the pool for a connection with
33
+ * the identifier equal to id, NULL is returned
34
+ * when no connection is found
35
+ */
36
+struct pool_con* pool_get(struct db_id* id)
37
+{
38
+	struct pool_con* ptr;
39
+
40
+	if (!id) {
41
+		LOG(L_ERR, "pool_get: Invalid parameter value\n");
42
+		return 0;
43
+	}
44
+
45
+	ptr = db_pool;
46
+	while (ptr) {
47
+		if (cmp_db_id(id, ptr->id)) {
48
+			ptr->ref++;
49
+			return ptr;
50
+		}
51
+		ptr = ptr->next;
52
+	}
53
+
54
+	return 0;
55
+}
56
+
57
+
58
+/*
59
+ * Insert a new connection into the pool
60
+ */
61
+void pool_insert(struct pool_con* con)
62
+{
63
+	if (!con) return;
64
+
65
+	con->next = db_pool;
66
+	db_pool = con;
67
+}
68
+
69
+
70
+/*
71
+ * Release connection from the pool, the function
72
+ * would return 1 when if the connection is not
73
+ * referenced anymore and thus can be closed and
74
+ * deleted by the backend. The function returns
75
+ * 0 if the connection should still be kept open
76
+ * because some other module is still using it.
77
+ * The function returns -1 if the connection is
78
+ * not in the pool.
79
+ */
80
+int pool_remove(struct pool_con* con)
81
+{
82
+	struct pool_con* ptr;
83
+
84
+	if (!con) return -2;
85
+
86
+	if (con->ref > 1) {
87
+		     /* There are still other users, just
88
+		      * decrease the reference count and return
89
+		      */
90
+		DBG("pool_remove: Connection still kept in the pool\n");
91
+		con->ref--;
92
+		return 0;
93
+	}
94
+
95
+	DBG("pool_remove: Removing connection from the pool\n");
96
+
97
+	if (db_pool == con) {
98
+		db_pool = db_pool->next;
99
+	} else {
100
+		ptr = db_pool;
101
+		while(ptr) {
102
+			if (ptr->next == con) break;
103
+			ptr = ptr->next;
104
+		}
105
+		if (!ptr) {
106
+			LOG(L_ERR, "pool_remove: Weird, connection not found in the pool\n");
107
+			return -1;
108
+		} else {
109
+			     /* Remove the connection from the pool */
110
+			ptr->next = con->next;
111
+		}
112
+	}
113
+
114
+	return 1;
115
+}
0 116
new file mode 100644
... ...
@@ -0,0 +1,72 @@
1
+/* 
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2001-2005 iptel.org
5
+ *
6
+ * This file is part of openser, a free SIP server.
7
+ *
8
+ * openser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * openser is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ */
22
+
23
+#ifndef _DB_POOL_H
24
+#define _DB_POOL_H
25
+
26
+#include "db_id.h"
27
+#include "db_con.h"
28
+
29
+
30
+/*
31
+ * This is a stub that contains all attributes
32
+ * that pool members must have, it is not really
33
+ * used, real connection structures are created
34
+ * by database backends. All such structures (
35
+ * created by the backends) must have these
36
+ * attributes.
37
+ */
38
+struct pool_con {
39
+	struct db_id* id;        /* Connection identifier */
40
+	unsigned int ref;        /* Reference count */
41
+	struct pool_con* next;   /* Next element in the pool */
42
+};
43
+
44
+
45
+/*
46
+ * Search the pool for a connection with
47
+ * the identifier equal to id, NULL is returned
48
+ * when no connection is found
49
+ */
50
+struct pool_con* pool_get(struct db_id* id);
51
+
52
+
53
+/*
54
+ * Insert a new connection into the pool
55
+ */
56
+void pool_insert(struct pool_con* con);
57
+
58
+
59
+/*
60
+ * Release connection from the pool, the function
61
+ * would return 1 when if the connection is not
62
+ * referenced anymore and thus can be closed and
63
+ * deleted by the backend. The function returns
64
+ * 0 if the connection should still be kept open
65
+ * because some other module is still using it.
66
+ * The function returns -1 if the connection is
67
+ * not in the pool.
68
+ */
69
+int pool_remove(struct pool_con* con);
70
+
71
+
72
+#endif /* _POOL_H */