db_id.c

Go to the documentation of this file.
00001 /* 
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2005 iptel.org
00005  * Copyright (C) 2007-2008 1&1 Internet AG
00006  *
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License 
00020  * along with this program; if not, write to the Free Software 
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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,     /* Scheme part */
00076                 ST_SLASH1,     /* First slash */
00077                 ST_SLASH2,     /* Second slash */
00078                 ST_USER_HOST,  /* Username or hostname */
00079                 ST_PASS_PORT,  /* Password or port part */
00080                 ST_HOST,       /* Hostname part */
00081                 ST_PORT,       /* Port part */
00082                 ST_DB          /* Database part */
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         /* Initialize all attributes to 0 */
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 }