Sat Mar 10 01:54:15 2012

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: 345682 $")
00033 
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"   /* use ast_config_AST_DB */
00036 #include <sys/time.h>
00037 #include <signal.h>
00038 #include <dirent.h>
00039 
00040 #include "asterisk/channel.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/dsp.h"
00044 #include "asterisk/astdb.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/manager.h"
00049 #include "db1-ast/include/db.h"
00050 
00051 /*** DOCUMENTATION
00052    <manager name="DBGet" language="en_US">
00053       <synopsis>
00054          Get DB Entry.
00055       </synopsis>
00056       <syntax>
00057          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00058          <parameter name="Family" required="true" />
00059          <parameter name="Key" required="true" />
00060       </syntax>
00061       <description>
00062       </description>
00063    </manager>
00064    <manager name="DBPut" language="en_US">
00065       <synopsis>
00066          Put DB entry.
00067       </synopsis>
00068       <syntax>
00069          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00070          <parameter name="Family" required="true" />
00071          <parameter name="Key" required="true" />
00072          <parameter name="Val" />
00073       </syntax>
00074       <description>
00075       </description>
00076    </manager>
00077    <manager name="DBDel" language="en_US">
00078       <synopsis>
00079          Delete DB entry.
00080       </synopsis>
00081       <syntax>
00082          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00083          <parameter name="Family" required="true" />
00084          <parameter name="Key" required="true" />
00085       </syntax>
00086       <description>
00087       </description>
00088    </manager>
00089    <manager name="DBDelTree" language="en_US">
00090       <synopsis>
00091          Delete DB Tree.
00092       </synopsis>
00093       <syntax>
00094          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00095          <parameter name="Family" required="true" />
00096          <parameter name="Key" />
00097       </syntax>
00098       <description>
00099       </description>
00100    </manager>
00101  ***/
00102 
00103 #define MAX_DB_FIELD 256
00104 
00105 static DB *astdb;
00106 AST_MUTEX_DEFINE_STATIC(dblock);
00107 static ast_cond_t dbcond;
00108 typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
00109 
00110 static void db_sync(void);
00111 
00112 static int dbinit(void) 
00113 {
00114    if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
00115       ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00116       return -1;
00117    }
00118    return 0;
00119 }
00120 
00121 
00122 static inline int keymatch(const char *key, const char *prefix)
00123 {
00124    int preflen = strlen(prefix);
00125    if (!preflen)
00126       return 1;
00127    if (!strcasecmp(key, prefix))
00128       return 1;
00129    if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00130       if (key[preflen] == '/')
00131          return 1;
00132    }
00133    return 0;
00134 }
00135 
00136 static inline int subkeymatch(const char *key, const char *suffix)
00137 {
00138    int suffixlen = strlen(suffix);
00139    if (suffixlen) {
00140       const char *subkey = key + strlen(key) - suffixlen;
00141       if (subkey < key)
00142          return 0;
00143       if (!strcasecmp(subkey, suffix))
00144          return 1;
00145    }
00146    return 0;
00147 }
00148 
00149 static const char *dbt_data2str(DBT *dbt)
00150 {
00151    char *data = "";
00152 
00153    if (dbt->size) {
00154       data = dbt->data;
00155       data[dbt->size - 1] = '\0';
00156    }
00157 
00158    return data;
00159 }
00160 
00161 static inline const char *dbt_data2str_full(DBT *dbt, const char *def)
00162 {
00163    return S_OR(dbt_data2str(dbt), def);
00164 }
00165 
00166 static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
00167 {
00168    DBT key = { 0, }, value = { 0, }, last_key = { 0, };
00169    int counter = 0;
00170    int res, last = 0;
00171    char last_key_s[MAX_DB_FIELD];
00172 
00173    ast_mutex_lock(&dblock);
00174    if (dbinit()) {
00175       ast_mutex_unlock(&dblock);
00176       return -1;
00177    }
00178 
00179    /* Somehow, the database can become corrupted such that astdb->seq will continue looping through
00180     * the database indefinitely. The pointer to last_key.data ends up getting re-used by the BDB lib
00181     * so this specifically queries for the last entry, makes a copy of the key, and then uses it as
00182     * a sentinel to avoid repeatedly looping over the list. */
00183 
00184    if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
00185       /* Empty database */
00186       ast_mutex_unlock(&dblock);
00187       return 0;
00188    }
00189 
00190    memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s)));
00191    last_key_s[last_key.size - 1] = '\0';
00192    for (res = astdb->seq(astdb, &key, &value, R_FIRST);
00193          !res;
00194          res = astdb->seq(astdb, &key, &value, R_NEXT)) {
00195       /* The callback might delete the key, so we have to check it before calling */
00196       last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s);
00197       counter += cb(&key, &value, filter, data);
00198       if (last) {
00199          break;
00200       }
00201    }
00202 
00203    if (sync) {
00204       db_sync();
00205    }
00206 
00207    ast_mutex_unlock(&dblock);
00208 
00209    return counter;
00210 }
00211 
00212 static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
00213 {
00214    int res = 0;
00215 
00216    if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) {
00217       astdb->del(astdb, key, 0);
00218       res = 1;
00219    }
00220    return res;
00221 }
00222 
00223 int ast_db_deltree(const char *family, const char *keytree)
00224 {
00225    char prefix[MAX_DB_FIELD];
00226 
00227    if (family) {
00228       if (keytree) {
00229          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00230       } else {
00231          snprintf(prefix, sizeof(prefix), "/%s", family);
00232       }
00233    } else if (keytree) {
00234       return -1;
00235    } else {
00236       prefix[0] = '\0';
00237    }
00238 
00239    return process_db_keys(db_deltree_cb, NULL, prefix, 1);
00240 }
00241 
00242 int ast_db_put(const char *family, const char *keys, const char *value)
00243 {
00244    char fullkey[MAX_DB_FIELD];
00245    DBT key, data;
00246    int res, fullkeylen;
00247 
00248    ast_mutex_lock(&dblock);
00249    if (dbinit()) {
00250       ast_mutex_unlock(&dblock);
00251       return -1;
00252    }
00253 
00254    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00255    memset(&key, 0, sizeof(key));
00256    memset(&data, 0, sizeof(data));
00257    key.data = fullkey;
00258    key.size = fullkeylen + 1;
00259    data.data = (char *) value;
00260    data.size = strlen(value) + 1;
00261    res = astdb->put(astdb, &key, &data, 0);
00262    db_sync();
00263    ast_mutex_unlock(&dblock);
00264    if (res)
00265       ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00266 
00267    return res;
00268 }
00269 
00270 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00271 {
00272    char fullkey[MAX_DB_FIELD] = "";
00273    DBT key, data;
00274    int res, fullkeylen;
00275 
00276    ast_mutex_lock(&dblock);
00277    if (dbinit()) {
00278       ast_mutex_unlock(&dblock);
00279       return -1;
00280    }
00281 
00282    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00283    memset(&key, 0, sizeof(key));
00284    memset(&data, 0, sizeof(data));
00285    memset(value, 0, valuelen);
00286    key.data = fullkey;
00287    key.size = fullkeylen + 1;
00288 
00289    res = astdb->get(astdb, &key, &data, 0);
00290 
00291    /* Be sure to NULL terminate our data either way */
00292    if (res) {
00293       ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00294    } else {
00295 #if 0
00296       printf("Got value of size %d\n", data.size);
00297 #endif
00298       if (data.size) {
00299          ((char *)data.data)[data.size - 1] = '\0';
00300          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00301          ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00302       } else {
00303          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00304       }
00305    }
00306 
00307    /* Data is not fully isolated for concurrency, so the lock must be extended
00308     * to after the copy to the output buffer. */
00309    ast_mutex_unlock(&dblock);
00310 
00311    return res;
00312 }
00313 
00314 int ast_db_del(const char *family, const char *keys)
00315 {
00316    char fullkey[MAX_DB_FIELD];
00317    DBT key;
00318    int res, fullkeylen;
00319 
00320    ast_mutex_lock(&dblock);
00321    if (dbinit()) {
00322       ast_mutex_unlock(&dblock);
00323       return -1;
00324    }
00325    
00326    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00327    memset(&key, 0, sizeof(key));
00328    key.data = fullkey;
00329    key.size = fullkeylen + 1;
00330    
00331    res = astdb->del(astdb, &key, 0);
00332    db_sync();
00333    
00334    ast_mutex_unlock(&dblock);
00335 
00336    if (res) {
00337       ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00338    }
00339    return res;
00340 }
00341 
00342 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00343 {
00344    int res;
00345 
00346    switch (cmd) {
00347    case CLI_INIT:
00348       e->command = "database put";
00349       e->usage =
00350          "Usage: database put <family> <key> <value>\n"
00351          "       Adds or updates an entry in the Asterisk database for\n"
00352          "       a given family, key, and value.\n";
00353       return NULL;
00354    case CLI_GENERATE:
00355       return NULL;
00356    }
00357 
00358    if (a->argc != 5)
00359       return CLI_SHOWUSAGE;
00360    res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
00361    if (res)  {
00362       ast_cli(a->fd, "Failed to update entry\n");
00363    } else {
00364       ast_cli(a->fd, "Updated database successfully\n");
00365    }
00366    return CLI_SUCCESS;
00367 }
00368 
00369 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00370 {
00371    int res;
00372    char tmp[MAX_DB_FIELD];
00373 
00374    switch (cmd) {
00375    case CLI_INIT:
00376       e->command = "database get";
00377       e->usage =
00378          "Usage: database get <family> <key>\n"
00379          "       Retrieves an entry in the Asterisk database for a given\n"
00380          "       family and key.\n";
00381       return NULL;
00382    case CLI_GENERATE:
00383       return NULL;
00384    }
00385 
00386    if (a->argc != 4)
00387       return CLI_SHOWUSAGE;
00388    res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
00389    if (res) {
00390       ast_cli(a->fd, "Database entry not found.\n");
00391    } else {
00392       ast_cli(a->fd, "Value: %s\n", tmp);
00393    }
00394    return CLI_SUCCESS;
00395 }
00396 
00397 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00398 {
00399    int res;
00400 
00401    switch (cmd) {
00402    case CLI_INIT:
00403       e->command = "database del";
00404       e->usage =
00405          "Usage: database del <family> <key>\n"
00406          "       Deletes an entry in the Asterisk database for a given\n"
00407          "       family and key.\n";
00408       return NULL;
00409    case CLI_GENERATE:
00410       return NULL;
00411    }
00412 
00413    if (a->argc != 4)
00414       return CLI_SHOWUSAGE;
00415    res = ast_db_del(a->argv[2], a->argv[3]);
00416    if (res) {
00417       ast_cli(a->fd, "Database entry does not exist.\n");
00418    } else {
00419       ast_cli(a->fd, "Database entry removed.\n");
00420    }
00421    return CLI_SUCCESS;
00422 }
00423 
00424 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00425 {
00426    int res;
00427 
00428    switch (cmd) {
00429    case CLI_INIT:
00430       e->command = "database deltree";
00431       e->usage =
00432          "Usage: database deltree <family> [keytree]\n"
00433          "   OR: database deltree <family>[/keytree]\n"
00434          "       Deletes a family or specific keytree within a family\n"
00435          "       in the Asterisk database.  The two arguments may be\n"
00436          "       separated by either a space or a slash.\n";
00437       return NULL;
00438    case CLI_GENERATE:
00439       return NULL;
00440    }
00441 
00442    if ((a->argc < 3) || (a->argc > 4))
00443       return CLI_SHOWUSAGE;
00444    if (a->argc == 4) {
00445       res = ast_db_deltree(a->argv[2], a->argv[3]);
00446    } else {
00447       res = ast_db_deltree(a->argv[2], NULL);
00448    }
00449    if (res < 0) {
00450       ast_cli(a->fd, "Database entries do not exist.\n");
00451    } else {
00452       ast_cli(a->fd, "%d database entries removed.\n",res);
00453    }
00454    return CLI_SUCCESS;
00455 }
00456 
00457 static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
00458 {
00459    struct ast_cli_args *a = data;
00460    const char *key_s = dbt_data2str_full(key, "<bad key>");
00461    const char *value_s = dbt_data2str_full(value, "<bad value>");
00462 
00463    if (keymatch(key_s, filter)) {
00464       ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00465       return 1;
00466    }
00467 
00468    return 0;
00469 }
00470 
00471 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00472 {
00473    char prefix[MAX_DB_FIELD];
00474    int counter = 0;
00475 
00476    switch (cmd) {
00477    case CLI_INIT:
00478       e->command = "database show";
00479       e->usage =
00480          "Usage: database show [family [keytree]]\n"
00481          "   OR: database show [family[/keytree]]\n"
00482          "       Shows Asterisk database contents, optionally restricted\n"
00483          "       to a given family, or family and keytree. The two arguments\n"
00484          "       may be separated either by a space or by a slash.\n";
00485       return NULL;
00486    case CLI_GENERATE:
00487       return NULL;
00488    }
00489 
00490    if (a->argc == 4) {
00491       /* Family and key tree */
00492       snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00493    } else if (a->argc == 3) {
00494       /* Family only */
00495       snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00496    } else if (a->argc == 2) {
00497       /* Neither */
00498       prefix[0] = '\0';
00499    } else {
00500       return CLI_SHOWUSAGE;
00501    }
00502 
00503    if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
00504       ast_cli(a->fd, "Database unavailable\n");
00505       return CLI_SUCCESS;
00506    }
00507 
00508    ast_cli(a->fd, "%d results found.\n", counter);
00509    return CLI_SUCCESS;
00510 }
00511 
00512 static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
00513 {
00514    struct ast_cli_args *a = data;
00515    const char *key_s = dbt_data2str_full(key, "<bad key>");
00516    const char *value_s = dbt_data2str_full(value, "<bad value>");
00517 
00518    if (subkeymatch(key_s, filter)) {
00519       ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00520       return 1;
00521    }
00522 
00523    return 0;
00524 }
00525 
00526 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00527 {
00528    char suffix[MAX_DB_FIELD];
00529    int counter = 0;
00530 
00531    switch (cmd) {
00532    case CLI_INIT:
00533       e->command = "database showkey";
00534       e->usage =
00535          "Usage: database showkey <keytree>\n"
00536          "       Shows Asterisk database contents, restricted to a given key.\n";
00537       return NULL;
00538    case CLI_GENERATE:
00539       return NULL;
00540    }
00541 
00542    if (a->argc == 3) {
00543       /* Key only */
00544       snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
00545    } else {
00546       return CLI_SHOWUSAGE;
00547    }
00548 
00549    if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
00550       ast_cli(a->fd, "Database unavailable\n");
00551       return CLI_SUCCESS;
00552    }
00553 
00554    ast_cli(a->fd, "%d results found.\n", counter);
00555    return CLI_SUCCESS;
00556 }
00557 
00558 static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
00559 {
00560    struct ast_db_entry **ret = data;
00561    struct ast_db_entry *cur;
00562    const char *key_s = dbt_data2str_full(key, "<bad key>");
00563    const char *value_s = dbt_data2str_full(value, "<bad value>");
00564    size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
00565 
00566    if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
00567       cur->next = *ret;
00568       cur->key = cur->data + value_slen;
00569       strcpy(cur->data, value_s);
00570       strcpy(cur->key, key_s);
00571       *ret = cur;
00572       return 1;
00573    }
00574 
00575    return 0;
00576 }
00577 
00578 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00579 {
00580    char prefix[MAX_DB_FIELD];
00581    struct ast_db_entry *ret = NULL;
00582 
00583    if (!ast_strlen_zero(family)) {
00584       if (!ast_strlen_zero(keytree)) {
00585          /* Family and key tree */
00586          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00587       } else {
00588          /* Family only */
00589          snprintf(prefix, sizeof(prefix), "/%s", family);
00590       }
00591    } else {
00592       prefix[0] = '\0';
00593    }
00594 
00595    if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) {
00596       ast_log(LOG_WARNING, "Database unavailable\n");
00597       return NULL;
00598    }
00599 
00600    return ret;
00601 }
00602 
00603 void ast_db_freetree(struct ast_db_entry *dbe)
00604 {
00605    struct ast_db_entry *last;
00606    while (dbe) {
00607       last = dbe;
00608       dbe = dbe->next;
00609       ast_free(last);
00610    }
00611 }
00612 
00613 static struct ast_cli_entry cli_database[] = {
00614    AST_CLI_DEFINE(handle_cli_database_show,    "Shows database contents"),
00615    AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00616    AST_CLI_DEFINE(handle_cli_database_get,     "Gets database value"),
00617    AST_CLI_DEFINE(handle_cli_database_put,     "Adds/updates database value"),
00618    AST_CLI_DEFINE(handle_cli_database_del,     "Removes database key/value"),
00619    AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
00620 };
00621 
00622 static int manager_dbput(struct mansession *s, const struct message *m)
00623 {
00624    const char *family = astman_get_header(m, "Family");
00625    const char *key = astman_get_header(m, "Key");
00626    const char *val = astman_get_header(m, "Val");
00627    int res;
00628 
00629    if (ast_strlen_zero(family)) {
00630       astman_send_error(s, m, "No family specified");
00631       return 0;
00632    }
00633    if (ast_strlen_zero(key)) {
00634       astman_send_error(s, m, "No key specified");
00635       return 0;
00636    }
00637 
00638    res = ast_db_put(family, key, S_OR(val, ""));
00639    if (res) {
00640       astman_send_error(s, m, "Failed to update entry");
00641    } else {
00642       astman_send_ack(s, m, "Updated database successfully");
00643    }
00644    return 0;
00645 }
00646 
00647 static int manager_dbget(struct mansession *s, const struct message *m)
00648 {
00649    const char *id = astman_get_header(m,"ActionID");
00650    char idText[256] = "";
00651    const char *family = astman_get_header(m, "Family");
00652    const char *key = astman_get_header(m, "Key");
00653    char tmp[MAX_DB_FIELD];
00654    int res;
00655 
00656    if (ast_strlen_zero(family)) {
00657       astman_send_error(s, m, "No family specified.");
00658       return 0;
00659    }
00660    if (ast_strlen_zero(key)) {
00661       astman_send_error(s, m, "No key specified.");
00662       return 0;
00663    }
00664 
00665    if (!ast_strlen_zero(id))
00666       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00667 
00668    res = ast_db_get(family, key, tmp, sizeof(tmp));
00669    if (res) {
00670       astman_send_error(s, m, "Database entry not found");
00671    } else {
00672       astman_send_ack(s, m, "Result will follow");
00673       astman_append(s, "Event: DBGetResponse\r\n"
00674             "Family: %s\r\n"
00675             "Key: %s\r\n"
00676             "Val: %s\r\n"
00677             "%s"
00678             "\r\n",
00679             family, key, tmp, idText);
00680       astman_append(s, "Event: DBGetComplete\r\n"
00681             "%s"
00682             "\r\n",
00683             idText);
00684    }
00685    return 0;
00686 }
00687 
00688 static int manager_dbdel(struct mansession *s, const struct message *m)
00689 {
00690    const char *family = astman_get_header(m, "Family");
00691    const char *key = astman_get_header(m, "Key");
00692    int res;
00693 
00694    if (ast_strlen_zero(family)) {
00695       astman_send_error(s, m, "No family specified.");
00696       return 0;
00697    }
00698 
00699    if (ast_strlen_zero(key)) {
00700       astman_send_error(s, m, "No key specified.");
00701       return 0;
00702    }
00703 
00704    res = ast_db_del(family, key);
00705    if (res)
00706       astman_send_error(s, m, "Database entry not found");
00707    else
00708       astman_send_ack(s, m, "Key deleted successfully");
00709 
00710    return 0;
00711 }
00712 
00713 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00714 {
00715    const char *family = astman_get_header(m, "Family");
00716    const char *key = astman_get_header(m, "Key");
00717    int res;
00718 
00719    if (ast_strlen_zero(family)) {
00720       astman_send_error(s, m, "No family specified.");
00721       return 0;
00722    }
00723 
00724    if (!ast_strlen_zero(key))
00725       res = ast_db_deltree(family, key);
00726    else
00727       res = ast_db_deltree(family, NULL);
00728 
00729    if (res < 0)
00730       astman_send_error(s, m, "Database entry not found");
00731    else
00732       astman_send_ack(s, m, "Key tree deleted successfully");
00733    
00734    return 0;
00735 }
00736 
00737 /*!
00738  * \internal
00739  * \brief Signal the astdb sync thread to do its thing.
00740  *
00741  * \note dblock is assumed to be held when calling this function.
00742  */
00743 static void db_sync(void)
00744 {
00745    ast_cond_signal(&dbcond);
00746 }
00747 
00748 /*!
00749  * \internal
00750  * \brief astdb sync thread
00751  *
00752  * This thread is in charge of syncing astdb to disk after a change.
00753  * By pushing it off to this thread to take care of, this I/O bound operation
00754  * will not block other threads from performing other critical processing.
00755  * If changes happen rapidly, this thread will also ensure that the sync
00756  * operations are rate limited.
00757  */
00758 static void *db_sync_thread(void *data)
00759 {
00760    ast_mutex_lock(&dblock);
00761    for (;;) {
00762       ast_cond_wait(&dbcond, &dblock);
00763       ast_mutex_unlock(&dblock);
00764       sleep(1);
00765       ast_mutex_lock(&dblock);
00766       astdb->sync(astdb, 0);
00767    }
00768 
00769    return NULL;
00770 }
00771 
00772 int astdb_init(void)
00773 {
00774    pthread_t dont_care;
00775 
00776    ast_cond_init(&dbcond, NULL);
00777    if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) {
00778       return -1;
00779    }
00780 
00781    dbinit();
00782    ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00783    ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00784    ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00785    ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00786    ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00787    return 0;
00788 }

Generated on Sat Mar 10 01:54:15 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7