db_id.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: db_id.c 5413 2009-01-05 12:27:49Z henningw $
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 
00024 /**
00025  * \file db/db_id.c
00026  * \ingroup db
00027  * \brief Functions for parsing a database URL and work with db identifier.
00028  */
00029 
00030 #include "db_id.h"
00031 #include "../dprint.h"
00032 #include "../mem/mem.h"
00033 #include "../ut.h"
00034 #include <stdlib.h>
00035 #include <string.h>
00036 
00037 
00038 /**
00039  * Duplicate a string
00040  * \param dst destination
00041  * \param begin start of the string
00042  * \param end end of the string
00043  */
00044 static int dupl_string(char** dst, const char* begin, const char* end)
00045 {
00046    if (*dst) pkg_free(*dst);
00047 
00048    *dst = pkg_malloc(end - begin + 1);
00049    if ((*dst) == NULL) {
00050       return -1;
00051    }
00052 
00053    memcpy(*dst, begin, end - begin);
00054    (*dst)[end - begin] = '\0';
00055    return 0;
00056 }
00057 
00058 
00059 /**
00060  * Parse a database URL of form 
00061  * scheme://[username[:password]@]hostname[:port]/database
00062  *
00063  * \param id filled id struct
00064  * \param url parsed URL
00065  * \return 0 if parsing was successful and -1 otherwise
00066  */
00067 static int parse_db_url(struct db_id* id, const str* url)
00068 {
00069 #define SHORTEST_DB_URL "s://a/b"
00070 #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
00071 
00072    enum state {
00073       ST_SCHEME,     /* Scheme part */
00074       ST_SLASH1,     /* First slash */
00075       ST_SLASH2,     /* Second slash */
00076       ST_USER_HOST,  /* Username or hostname */
00077       ST_PASS_PORT,  /* Password or port part */
00078       ST_HOST,       /* Hostname part */
00079       ST_PORT,       /* Port part */
00080       ST_DB          /* Database part */
00081    };
00082 
00083    enum state st;
00084    unsigned int len, i;
00085    const char* begin;
00086    char* prev_token;
00087 
00088    prev_token = 0;
00089 
00090    if (!id || !url || !url->s) {
00091       goto err;
00092    }
00093    
00094    len = url->len;
00095    if (len < SHORTEST_DB_URL_LEN) {
00096       goto err;
00097    }
00098    
00099    /* Initialize all attributes to 0 */
00100    memset(id, 0, sizeof(struct db_id));
00101    st = ST_SCHEME;
00102    begin = url->s;
00103 
00104    for(i = 0; i < len; i++) {
00105       switch(st) {
00106       case ST_SCHEME:
00107          switch(url->s[i]) {
00108          case ':':
00109             st = ST_SLASH1;
00110             if (dupl_string(&id->scheme, begin, url->s + i) < 0) goto err;
00111             break;
00112          }
00113          break;
00114 
00115       case ST_SLASH1:
00116          switch(url->s[i]) {
00117          case '/':
00118             st = ST_SLASH2;
00119             break;
00120 
00121          default:
00122             goto err;
00123          }
00124          break;
00125 
00126       case ST_SLASH2:
00127          switch(url->s[i]) {
00128          case '/':
00129             st = ST_USER_HOST;
00130             begin = url->s + i + 1;
00131             break;
00132             
00133          default:
00134             goto err;
00135          }
00136          break;
00137 
00138       case ST_USER_HOST:
00139          switch(url->s[i]) {
00140          case '@':
00141             st = ST_HOST;
00142             if (dupl_string(&id->username, begin, url->s + i) < 0) goto err;
00143             begin = url->s + i + 1;
00144             break;
00145 
00146          case ':':
00147             st = ST_PASS_PORT;
00148             if (dupl_string(&prev_token, begin, url->s + i) < 0) goto err;
00149             begin = url->s + i + 1;
00150             break;
00151 
00152          case '/':
00153             if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00154             if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00155             return 0;
00156          }
00157          break;
00158 
00159       case ST_PASS_PORT:
00160          switch(url->s[i]) {
00161          case '@':
00162             st = ST_HOST;
00163             id->username = prev_token;
00164             if (dupl_string(&id->password, begin, url->s + i) < 0) goto err;
00165             begin = url->s + i + 1;
00166             break;
00167 
00168          case '/':
00169             id->host = prev_token;
00170             id->port = str2s(begin, url->s + i - begin, 0);
00171             if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00172             return 0;
00173          }
00174          break;
00175 
00176       case ST_HOST:
00177          switch(url->s[i]) {
00178          case ':':
00179             st = ST_PORT;
00180             if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00181             begin = url->s + i + 1;
00182             break;
00183 
00184          case '/':
00185             if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
00186             if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00187             return 0;
00188          }
00189          break;
00190 
00191       case ST_PORT:
00192          switch(url->s[i]) {
00193          case '/':
00194             id->port = str2s(begin, url->s + i - begin, 0);
00195             if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
00196             return 0;
00197          }
00198          break;
00199          
00200       case ST_DB:
00201          break;
00202       }
00203    }
00204 
00205    if (st != ST_DB) goto err;
00206    return 0;
00207 
00208  err:
00209    if (id->scheme) pkg_free(id->scheme);
00210    if (id->username) pkg_free(id->username);
00211    if (id->password) pkg_free(id->password);
00212    if (id->host) pkg_free(id->host);
00213    if (id->database) pkg_free(id->database);
00214    if (prev_token) pkg_free(prev_token);
00215    return -1;
00216 }
00217 
00218 
00219 /**
00220  * Create a new connection identifier
00221  * \param url database URL
00222  * \return connection identifier, or zero on error
00223  */
00224 struct db_id* new_db_id(const str* url)
00225 {
00226    struct db_id* ptr;
00227 
00228    if (!url || !url->s) {
00229       LM_ERR("invalid parameter\n");
00230       return 0;
00231    }
00232 
00233    ptr = (struct db_id*)pkg_malloc(sizeof(struct db_id));
00234    if (!ptr) {
00235       LM_ERR("no private memory left\n");
00236       goto err;
00237    }
00238    memset(ptr, 0, sizeof(struct db_id));
00239 
00240    if (parse_db_url(ptr, url) < 0) {
00241       LM_ERR("error while parsing database URL: '%.*s' \n", url->len, url->s);
00242       goto err;
00243    }
00244 
00245    return ptr;
00246 
00247  err:
00248    if (ptr) pkg_free(ptr);
00249    return 0;
00250 }
00251 
00252 
00253 /**
00254  * Compare two connection identifiers
00255  * \param id1 first identifier
00256  * \param id2 second identifier
00257  * \return one if both are equal, zero otherwise
00258  */
00259 unsigned char cmp_db_id(const struct db_id* id1, const struct db_id* id2)
00260 {
00261    if (!id1 || !id2) return 0;
00262    if (id1->port != id2->port) return 0;
00263 
00264    if (strcmp(id1->scheme, id2->scheme)) return 0;
00265    if (id1->username!=0 && id2->username!=0) {
00266       if (strcmp(id1->username, id2->username)) return 0;
00267    } else {
00268       if (id1->username!=0 || id2->username!=0) return 0;
00269    }
00270    if (id1->password!=0 && id2->password!=0) {
00271       if(strcmp(id1->password, id2->password)) return 0;
00272    } else {
00273       if (id1->password!=0 || id2->password!=0) return 0;
00274    }
00275    if (strcasecmp(id1->host, id2->host)) return 0;
00276    if (strcmp(id1->database, id2->database)) return 0;
00277    return 1;
00278 }
00279 
00280 
00281 /**
00282  * Free a connection identifier
00283  * \param id identifier
00284  */
00285 void free_db_id(struct db_id* id)
00286 {
00287    if (!id) return;
00288 
00289    if (id->scheme) pkg_free(id->scheme);
00290    if (id->username) pkg_free(id->username);
00291    if (id->password) pkg_free(id->password);
00292    if (id->host) pkg_free(id->host);
00293    if (id->database) pkg_free(id->database);
00294    pkg_free(id);
00295 }

Generated on Mon May 21 18:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6