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