Sat Aug 6 00:39:28 2011

Asterisk developer's documentation


db.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief ASTdb Management
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  *
00025  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
00026  * with GPL.  To avoid having to make another exception (and complicate 
00027  * licensing even further) we elect to use DB1 which is BSD licensed 
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 182449 $")
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <sys/time.h>
00038 #include <signal.h>
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <dirent.h>
00042 
00043 #include "asterisk/channel.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/app.h"
00046 #include "asterisk/dsp.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/options.h"
00049 #include "asterisk/astdb.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/manager.h"
00054 #include "db1-ast/include/db.h"
00055 
00056 #ifdef __CYGWIN__
00057 #define dbopen __dbopen
00058 #endif
00059 
00060 static DB *astdb;
00061 AST_MUTEX_DEFINE_STATIC(dblock);
00062 
00063 static int dbinit(void) 
00064 {
00065    if (!astdb && !(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
00066       ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00067       return -1;
00068    }
00069    return 0;
00070 }
00071 
00072 
00073 static inline int keymatch(const char *key, const char *prefix)
00074 {
00075    int preflen = strlen(prefix);
00076    if (!preflen)
00077       return 1;
00078    if (!strcasecmp(key, prefix))
00079       return 1;
00080    if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00081       if (key[preflen] == '/')
00082          return 1;
00083    }
00084    return 0;
00085 }
00086 
00087 static inline int subkeymatch(const char *key, const char *suffix)
00088 {
00089    int suffixlen = strlen(suffix);
00090    if (suffixlen) {
00091       const char *subkey = key + strlen(key) - suffixlen;
00092       if (subkey < key)
00093          return 0;
00094       if (!strcasecmp(subkey, suffix))
00095          return 1;
00096    }
00097    return 0;
00098 }
00099 
00100 int ast_db_deltree(const char *family, const char *keytree)
00101 {
00102    char prefix[256];
00103    DBT key, data;
00104    char *keys;
00105    int res;
00106    int pass;
00107    
00108    if (family) {
00109       if (keytree) {
00110          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00111       } else {
00112          snprintf(prefix, sizeof(prefix), "/%s", family);
00113       }
00114    } else if (keytree) {
00115       return -1;
00116    } else {
00117       prefix[0] = '\0';
00118    }
00119    
00120    ast_mutex_lock(&dblock);
00121    if (dbinit()) {
00122       ast_mutex_unlock(&dblock);
00123       return -1;
00124    }
00125    
00126    memset(&key, 0, sizeof(key));
00127    memset(&data, 0, sizeof(data));
00128    pass = 0;
00129    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00130       if (key.size) {
00131          keys = key.data;
00132          keys[key.size - 1] = '\0';
00133       } else {
00134          keys = "<bad key>";
00135       }
00136       if (keymatch(keys, prefix)) {
00137          astdb->del(astdb, &key, 0);
00138       }
00139    }
00140    astdb->sync(astdb, 0);
00141    ast_mutex_unlock(&dblock);
00142    return 0;
00143 }
00144 
00145 int ast_db_put(const char *family, const char *keys, char *value)
00146 {
00147    char fullkey[256];
00148    DBT key, data;
00149    int res, fullkeylen;
00150 
00151    ast_mutex_lock(&dblock);
00152    if (dbinit()) {
00153       ast_mutex_unlock(&dblock);
00154       return -1;
00155    }
00156 
00157    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00158    memset(&key, 0, sizeof(key));
00159    memset(&data, 0, sizeof(data));
00160    key.data = fullkey;
00161    key.size = fullkeylen + 1;
00162    data.data = value;
00163    data.size = strlen(value) + 1;
00164    res = astdb->put(astdb, &key, &data, 0);
00165    astdb->sync(astdb, 0);
00166    ast_mutex_unlock(&dblock);
00167    if (res)
00168       ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00169    return res;
00170 }
00171 
00172 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00173 {
00174    char fullkey[256] = "";
00175    DBT key, data;
00176    int res, fullkeylen;
00177 
00178    ast_mutex_lock(&dblock);
00179    if (dbinit()) {
00180       ast_mutex_unlock(&dblock);
00181       return -1;
00182    }
00183 
00184    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00185    memset(&key, 0, sizeof(key));
00186    memset(&data, 0, sizeof(data));
00187    memset(value, 0, valuelen);
00188    key.data = fullkey;
00189    key.size = fullkeylen + 1;
00190 
00191    res = astdb->get(astdb, &key, &data, 0);
00192 
00193    /* Be sure to NULL terminate our data either way */
00194    if (res) {
00195       if (option_debug)
00196          ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00197    } else {
00198 #if 0
00199       printf("Got value of size %d\n", data.size);
00200 #endif
00201       if (data.size) {
00202          ((char *)data.data)[data.size - 1] = '\0';
00203          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00204          ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00205       } else {
00206          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00207       }
00208    }
00209 
00210    /* Data is not fully isolated for concurrency, so the lock must be extended
00211     * to after the copy to the output buffer. */
00212    ast_mutex_unlock(&dblock);
00213 
00214    return res;
00215 }
00216 
00217 int ast_db_del(const char *family, const char *keys)
00218 {
00219    char fullkey[256];
00220    DBT key;
00221    int res, fullkeylen;
00222 
00223    ast_mutex_lock(&dblock);
00224    if (dbinit()) {
00225       ast_mutex_unlock(&dblock);
00226       return -1;
00227    }
00228    
00229    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00230    memset(&key, 0, sizeof(key));
00231    key.data = fullkey;
00232    key.size = fullkeylen + 1;
00233    
00234    res = astdb->del(astdb, &key, 0);
00235    astdb->sync(astdb, 0);
00236    
00237    ast_mutex_unlock(&dblock);
00238 
00239    if (res && option_debug)
00240       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00241    return res;
00242 }
00243 
00244 static int database_put(int fd, int argc, char *argv[])
00245 {
00246    int res;
00247    if (argc != 5)
00248       return RESULT_SHOWUSAGE;
00249    res = ast_db_put(argv[2], argv[3], argv[4]);
00250    if (res)  {
00251       ast_cli(fd, "Failed to update entry\n");
00252    } else {
00253       ast_cli(fd, "Updated database successfully\n");
00254    }
00255    return RESULT_SUCCESS;
00256 }
00257 
00258 static int database_get(int fd, int argc, char *argv[])
00259 {
00260    int res;
00261    char tmp[256];
00262    if (argc != 4)
00263       return RESULT_SHOWUSAGE;
00264    res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
00265    if (res) {
00266       ast_cli(fd, "Database entry not found.\n");
00267    } else {
00268       ast_cli(fd, "Value: %s\n", tmp);
00269    }
00270    return RESULT_SUCCESS;
00271 }
00272 
00273 static int database_del(int fd, int argc, char *argv[])
00274 {
00275    int res;
00276    if (argc != 4)
00277       return RESULT_SHOWUSAGE;
00278    res = ast_db_del(argv[2], argv[3]);
00279    if (res) {
00280       ast_cli(fd, "Database entry does not exist.\n");
00281    } else {
00282       ast_cli(fd, "Database entry removed.\n");
00283    }
00284    return RESULT_SUCCESS;
00285 }
00286 
00287 static int database_deltree(int fd, int argc, char *argv[])
00288 {
00289    int res;
00290    if ((argc < 3) || (argc > 4))
00291       return RESULT_SHOWUSAGE;
00292    if (argc == 4) {
00293       res = ast_db_deltree(argv[2], argv[3]);
00294    } else {
00295       res = ast_db_deltree(argv[2], NULL);
00296    }
00297    if (res) {
00298       ast_cli(fd, "Database entries do not exist.\n");
00299    } else {
00300       ast_cli(fd, "Database entries removed.\n");
00301    }
00302    return RESULT_SUCCESS;
00303 }
00304 
00305 static int database_show(int fd, int argc, char *argv[])
00306 {
00307    char prefix[256];
00308    DBT key, data;
00309    char *keys, *values;
00310    int res;
00311    int pass;
00312 
00313    if (argc == 4) {
00314       /* Family and key tree */
00315       snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
00316    } else if (argc == 3) {
00317       /* Family only */
00318       snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
00319    } else if (argc == 2) {
00320       /* Neither */
00321       prefix[0] = '\0';
00322    } else {
00323       return RESULT_SHOWUSAGE;
00324    }
00325    ast_mutex_lock(&dblock);
00326    if (dbinit()) {
00327       ast_mutex_unlock(&dblock);
00328       ast_cli(fd, "Database unavailable\n");
00329       return RESULT_SUCCESS;  
00330    }
00331    memset(&key, 0, sizeof(key));
00332    memset(&data, 0, sizeof(data));
00333    pass = 0;
00334    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00335       if (key.size) {
00336          keys = key.data;
00337          keys[key.size - 1] = '\0';
00338       } else {
00339          keys = "<bad key>";
00340       }
00341       if (data.size) {
00342          values = data.data;
00343          values[data.size - 1]='\0';
00344       } else {
00345          values = "<bad value>";
00346       }
00347       if (keymatch(keys, prefix)) {
00348             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00349       }
00350    }
00351    ast_mutex_unlock(&dblock);
00352    return RESULT_SUCCESS;  
00353 }
00354 
00355 static int database_showkey(int fd, int argc, char *argv[])
00356 {
00357    char suffix[256];
00358    DBT key, data;
00359    char *keys, *values;
00360    int res;
00361    int pass;
00362 
00363    if (argc == 3) {
00364       /* Key only */
00365       snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
00366    } else {
00367       return RESULT_SHOWUSAGE;
00368    }
00369    ast_mutex_lock(&dblock);
00370    if (dbinit()) {
00371       ast_mutex_unlock(&dblock);
00372       ast_cli(fd, "Database unavailable\n");
00373       return RESULT_SUCCESS;  
00374    }
00375    memset(&key, 0, sizeof(key));
00376    memset(&data, 0, sizeof(data));
00377    pass = 0;
00378    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00379       if (key.size) {
00380          keys = key.data;
00381          keys[key.size - 1] = '\0';
00382       } else {
00383          keys = "<bad key>";
00384       }
00385       if (data.size) {
00386          values = data.data;
00387          values[data.size - 1]='\0';
00388       } else {
00389          values = "<bad value>";
00390       }
00391       if (subkeymatch(keys, suffix)) {
00392             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00393       }
00394    }
00395    ast_mutex_unlock(&dblock);
00396    return RESULT_SUCCESS;  
00397 }
00398 
00399 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00400 {
00401    char prefix[256];
00402    DBT key, data;
00403    char *keys, *values;
00404    int values_len;
00405    int res;
00406    int pass;
00407    struct ast_db_entry *last = NULL;
00408    struct ast_db_entry *cur, *ret=NULL;
00409 
00410    if (!ast_strlen_zero(family)) {
00411       if (!ast_strlen_zero(keytree)) {
00412          /* Family and key tree */
00413          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00414       } else {
00415          /* Family only */
00416          snprintf(prefix, sizeof(prefix), "/%s", family);
00417       }
00418    } else {
00419       prefix[0] = '\0';
00420    }
00421    ast_mutex_lock(&dblock);
00422    if (dbinit()) {
00423       ast_mutex_unlock(&dblock);
00424       ast_log(LOG_WARNING, "Database unavailable\n");
00425       return NULL;   
00426    }
00427    memset(&key, 0, sizeof(key));
00428    memset(&data, 0, sizeof(data));
00429    pass = 0;
00430    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00431       if (key.size) {
00432          keys = key.data;
00433          keys[key.size - 1] = '\0';
00434       } else {
00435          keys = "<bad key>";
00436       }
00437       if (data.size) {
00438          values = data.data;
00439          values[data.size - 1] = '\0';
00440       } else {
00441          values = "<bad value>";
00442       }
00443       values_len = strlen(values) + 1;
00444       if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) {
00445          cur->next = NULL;
00446          cur->key = cur->data + values_len;
00447          strcpy(cur->data, values);
00448          strcpy(cur->key, keys);
00449          if (last) {
00450             last->next = cur;
00451          } else {
00452             ret = cur;
00453          }
00454          last = cur;
00455       }
00456    }
00457    ast_mutex_unlock(&dblock);
00458    return ret; 
00459 }
00460 
00461 void ast_db_freetree(struct ast_db_entry *dbe)
00462 {
00463    struct ast_db_entry *last;
00464    while (dbe) {
00465       last = dbe;
00466       dbe = dbe->next;
00467       free(last);
00468    }
00469 }
00470 
00471 static char database_show_usage[] =
00472 "Usage: database show [family [keytree]]\n"
00473 "       Shows Asterisk database contents, optionally restricted\n"
00474 "to a given family, or family and keytree.\n";
00475 
00476 static char database_showkey_usage[] =
00477 "Usage: database showkey <keytree>\n"
00478 "       Shows Asterisk database contents, restricted to a given key.\n";
00479 
00480 static char database_put_usage[] =
00481 "Usage: database put <family> <key> <value>\n"
00482 "       Adds or updates an entry in the Asterisk database for\n"
00483 "a given family, key, and value.\n";
00484 
00485 static char database_get_usage[] =
00486 "Usage: database get <family> <key>\n"
00487 "       Retrieves an entry in the Asterisk database for a given\n"
00488 "family and key.\n";
00489 
00490 static char database_del_usage[] =
00491 "Usage: database del <family> <key>\n"
00492 "       Deletes an entry in the Asterisk database for a given\n"
00493 "family and key.\n";
00494 
00495 static char database_deltree_usage[] =
00496 "Usage: database deltree <family> [keytree]\n"
00497 "       Deletes a family or specific keytree within a family\n"
00498 "in the Asterisk database.\n";
00499 
00500 struct ast_cli_entry cli_database[] = {
00501    { { "database", "show", NULL },
00502    database_show, "Shows database contents",
00503    database_show_usage },
00504 
00505    { { "database", "showkey", NULL },
00506    database_showkey, "Shows database contents",
00507    database_showkey_usage },
00508 
00509    { { "database", "get", NULL },
00510    database_get, "Gets database value",
00511    database_get_usage },
00512 
00513    { { "database", "put", NULL },
00514    database_put, "Adds/updates database value",
00515    database_put_usage },
00516 
00517    { { "database", "del", NULL },
00518    database_del, "Removes database key/value",
00519    database_del_usage },
00520 
00521    { { "database", "deltree", NULL },
00522    database_deltree, "Removes database keytree/values",
00523    database_deltree_usage },
00524 };
00525 
00526 static int manager_dbput(struct mansession *s, const struct message *m)
00527 {
00528    const char *family = astman_get_header(m, "Family");
00529    const char *key = astman_get_header(m, "Key");
00530    const char *val = astman_get_header(m, "Val");
00531    int res;
00532 
00533    if (ast_strlen_zero(family)) {
00534       astman_send_error(s, m, "No family specified");
00535       return 0;
00536    }
00537    if (ast_strlen_zero(key)) {
00538       astman_send_error(s, m, "No key specified");
00539       return 0;
00540    }
00541 
00542    res = ast_db_put(family, key, (char *) S_OR(val, ""));
00543    if (res) {
00544       astman_send_error(s, m, "Failed to update entry");
00545    } else {
00546       astman_send_ack(s, m, "Updated database successfully");
00547    }
00548    return 0;
00549 }
00550 
00551 static int manager_dbget(struct mansession *s, const struct message *m)
00552 {
00553    const char *id = astman_get_header(m,"ActionID");
00554    char idText[256] = "";
00555    const char *family = astman_get_header(m, "Family");
00556    const char *key = astman_get_header(m, "Key");
00557    char tmp[256];
00558    int res;
00559 
00560    if (ast_strlen_zero(family)) {
00561       astman_send_error(s, m, "No family specified.");
00562       return 0;
00563    }
00564    if (ast_strlen_zero(key)) {
00565       astman_send_error(s, m, "No key specified.");
00566       return 0;
00567    }
00568 
00569    if (!ast_strlen_zero(id))
00570       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00571 
00572    res = ast_db_get(family, key, tmp, sizeof(tmp));
00573    if (res) {
00574       astman_send_error(s, m, "Database entry not found");
00575    } else {
00576       astman_send_ack(s, m, "Result will follow");
00577       astman_append(s, "Event: DBGetResponse\r\n"
00578             "Family: %s\r\n"
00579             "Key: %s\r\n"
00580             "Val: %s\r\n"
00581             "%s"
00582             "\r\n",
00583             family, key, tmp, idText);
00584    }
00585    return 0;
00586 }
00587 
00588 int astdb_init(void)
00589 {
00590    dbinit();
00591    ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
00592    ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
00593    ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
00594    return 0;
00595 }

Generated on Sat Aug 6 00:39:28 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7