00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00030 #include "db.h"
00031 #include "db_id.h"
00032 #include "../../dprint.h"
00033 #include "../../mem/mem.h"
00034 #include "../../pt.h"
00035 #include "../../ut.h"
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039
00046 static int dupl_string(char** dst, const char* begin, const char* end)
00047 {
00048 if (*dst) pkg_free(*dst);
00049
00050 *dst = pkg_malloc(end - begin + 1);
00051 if ((*dst) == NULL) {
00052 return -1;
00053 }
00054
00055 memcpy(*dst, begin, end - begin);
00056 (*dst)[end - begin] = '\0';
00057 return 0;
00058 }
00059
00060
00069 static int parse_db_url(struct db_id* id, const str* url)
00070 {
00071 #define SHORTEST_DB_URL "s://a/b"
00072 #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
00073
00074 enum state {
00075 ST_SCHEME,
00076 ST_SLASH1,
00077 ST_SLASH2,
00078 ST_USER_HOST,
00079 ST_PASS_PORT,
00080 ST_HOST,
00081 ST_PORT,
00082 ST_DB
00083 };
00084
00085 enum state st;
00086 unsigned int len, i;
00087 const char* begin;
00088 char* prev_token;
00089
00090 prev_token = 0;
00091
00092 if (!id || !url || !url->s) {
00093 goto err;
00094 }
00095
00096 len = url->len;
00097 if (len < SHORTEST_DB_URL_LEN) {
00098 goto err;
00099 }
00100
00101
00102 memset(id, 0, sizeof(struct db_id));
00103 st = ST_SCHEME;
00104 begin = url->s;
00105
00106 for(i = 0; i < len; i++) {
00107 switch(st) {
00108 case ST_SCHEME:
00109 switch(url->s[i]) {
00110 case ':':
00111 st = ST_SLASH1;
00112 if (dupl_string(&id->scheme, begin, url->s + i) < 0) goto err;
00113 break;
00114 }
00115 break;
00116
00117 case ST_SLASH1:
00118 switch(url->s[i]) {
00119 case '/':
00120 st = ST_SLASH2;
00121 break;
00122
00123 default:
00124 goto err;
00125 }
00126 break;
00127
00128 case ST_SLASH2:
00129 switch(url->s[i]) {
00130 case '/':
00131 st = ST_USER_HOST;
00132 begin = url->s + i + 1;
00133 break;
00134
00135 default:
00136 goto err;
00137 }
00138 break;
00139
00140 case ST_USER_HOST:
00141 switch(url->s[i]) {
00142 case '@':
00143 st = ST_HOST;
00144 if (dupl_string(&id->username, begin, url->s + i) < 0) goto err;
00145 begin = url->s + i + 1;
00146 break;
00147
00148 case ':':
00149 st = ST_PASS_PORT;
00150 if (dupl_string(&prev_token, begin, url->s + i) < 0) goto err;
00151 begin = url->s + i + 1;
00152 break;
00153
00154 case '/':
00155 if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00156 if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00157 return 0;
00158 }
00159 break;
00160
00161 case ST_PASS_PORT:
00162 switch(url->s[i]) {
00163 case '@':
00164 st = ST_HOST;
00165 id->username = prev_token;
00166 prev_token = 0;
00167 if (dupl_string(&id->password, begin, url->s + i) < 0) goto err;
00168 begin = url->s + i + 1;
00169 break;
00170
00171 case '/':
00172 id->host = prev_token;
00173 prev_token = 0;
00174 id->port = str2s(begin, url->s + i - begin, 0);
00175 if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00176 return 0;
00177 }
00178 break;
00179
00180 case ST_HOST:
00181 switch(url->s[i]) {
00182 case ':':
00183 st = ST_PORT;
00184 if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00185 begin = url->s + i + 1;
00186 break;
00187
00188 case '/':
00189 if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00190 if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00191 return 0;
00192 }
00193 break;
00194
00195 case ST_PORT:
00196 switch(url->s[i]) {
00197 case '/':
00198 id->port = str2s(begin, url->s + i - begin, 0);
00199 if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00200 return 0;
00201 }
00202 break;
00203
00204 case ST_DB:
00205 break;
00206 }
00207 }
00208
00209 if (st != ST_DB) goto err;
00210 return 0;
00211
00212 err:
00213 if (!id) goto end;
00214 if (id->scheme) pkg_free(id->scheme);
00215 if (id->username) pkg_free(id->username);
00216 if (id->password) pkg_free(id->password);
00217 if (id->host) pkg_free(id->host);
00218 if (id->database) pkg_free(id->database);
00219 memset(id, 0, sizeof(struct db_id));
00220 if (prev_token) pkg_free(prev_token);
00221 end:
00222 return -1;
00223 }
00224
00225
00232 struct db_id* new_db_id(const str* url, db_pooling_t pooling)
00233 {
00234 static int poolid=0;
00235 struct db_id* ptr;
00236
00237 if (!url || !url->s) {
00238 LM_ERR("invalid parameter\n");
00239 return 0;
00240 }
00241
00242 ptr = (struct db_id*)pkg_malloc(sizeof(struct db_id));
00243 if (!ptr) {
00244 LM_ERR("no private memory left\n");
00245 goto err;
00246 }
00247 memset(ptr, 0, sizeof(struct db_id));
00248
00249 if (parse_db_url(ptr, url) < 0) {
00250 LM_ERR("error while parsing database URL: '%.*s' \n", url->len, url->s);
00251 goto err;
00252 }
00253
00254 if (pooling == DB_POOLING_NONE) ptr->poolid = ++poolid;
00255 else ptr->poolid = 0;
00256 ptr->pid = my_pid();
00257
00258 return ptr;
00259
00260 err:
00261 if (ptr) pkg_free(ptr);
00262 return 0;
00263 }
00264
00265
00272 unsigned char cmp_db_id(const struct db_id* id1, const struct db_id* id2)
00273 {
00274 if (!id1 || !id2) return 0;
00275 if (id1->port != id2->port) return 0;
00276
00277 if (strcmp(id1->scheme, id2->scheme)) return 0;
00278 if (id1->username!=0 && id2->username!=0) {
00279 if (strcmp(id1->username, id2->username)) return 0;
00280 } else {
00281 if (id1->username!=0 || id2->username!=0) return 0;
00282 }
00283 if (id1->password!=0 && id2->password!=0) {
00284 if(strcmp(id1->password, id2->password)) return 0;
00285 } else {
00286 if (id1->password!=0 || id2->password!=0) return 0;
00287 }
00288 if (strcasecmp(id1->host, id2->host)) return 0;
00289 if (strcmp(id1->database, id2->database)) return 0;
00290 if(id1->pid!=id2->pid) {
00291 LM_DBG("identical DB URLs, but different DB connection pid [%d/%d]\n",
00292 id1->pid, id2->pid);
00293 return 0;
00294 }
00295 if(id1->poolid!=id2->poolid) {
00296 LM_DBG("identical DB URLs, but different poolids [%d/%d]\n",
00297 id1->poolid, id2->poolid);
00298 return 0;
00299 }
00300 return 1;
00301 }
00302
00303
00308 void free_db_id(struct db_id* id)
00309 {
00310 if (!id) return;
00311
00312 if (id->scheme) pkg_free(id->scheme);
00313 if (id->username) pkg_free(id->username);
00314 if (id->password) pkg_free(id->password);
00315 if (id->host) pkg_free(id->host);
00316 if (id->database) pkg_free(id->database);
00317 pkg_free(id);
00318 }