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 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 322981 $")
00033
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"
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
00052
00053
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 #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
00180
00181
00182
00183
00184 if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
00185
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
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
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
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
00308
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 " Deletes a family or specific keytree within a family\n"
00434 " in the Asterisk database.\n";
00435 return NULL;
00436 case CLI_GENERATE:
00437 return NULL;
00438 }
00439
00440 if ((a->argc < 3) || (a->argc > 4))
00441 return CLI_SHOWUSAGE;
00442 if (a->argc == 4) {
00443 res = ast_db_deltree(a->argv[2], a->argv[3]);
00444 } else {
00445 res = ast_db_deltree(a->argv[2], NULL);
00446 }
00447 if (res < 0) {
00448 ast_cli(a->fd, "Database entries do not exist.\n");
00449 } else {
00450 ast_cli(a->fd, "%d database entries removed.\n",res);
00451 }
00452 return CLI_SUCCESS;
00453 }
00454
00455 static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
00456 {
00457 struct ast_cli_args *a = data;
00458 const char *key_s = dbt_data2str_full(key, "<bad key>");
00459 const char *value_s = dbt_data2str_full(value, "<bad value>");
00460
00461 if (keymatch(key_s, filter)) {
00462 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00463 return 1;
00464 }
00465
00466 return 0;
00467 }
00468
00469 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00470 {
00471 char prefix[MAX_DB_FIELD];
00472 int counter = 0;
00473
00474 switch (cmd) {
00475 case CLI_INIT:
00476 e->command = "database show";
00477 e->usage =
00478 "Usage: database show [family [keytree]]\n"
00479 " Shows Asterisk database contents, optionally restricted\n"
00480 " to a given family, or family and keytree.\n";
00481 return NULL;
00482 case CLI_GENERATE:
00483 return NULL;
00484 }
00485
00486 if (a->argc == 4) {
00487
00488 snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00489 } else if (a->argc == 3) {
00490
00491 snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00492 } else if (a->argc == 2) {
00493
00494 prefix[0] = '\0';
00495 } else {
00496 return CLI_SHOWUSAGE;
00497 }
00498
00499 if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
00500 ast_cli(a->fd, "Database unavailable\n");
00501 return CLI_SUCCESS;
00502 }
00503
00504 ast_cli(a->fd, "%d results found.\n", counter);
00505 return CLI_SUCCESS;
00506 }
00507
00508 static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
00509 {
00510 struct ast_cli_args *a = data;
00511 const char *key_s = dbt_data2str_full(key, "<bad key>");
00512 const char *value_s = dbt_data2str_full(value, "<bad value>");
00513
00514 if (subkeymatch(key_s, filter)) {
00515 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00516 return 1;
00517 }
00518
00519 return 0;
00520 }
00521
00522 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00523 {
00524 char suffix[MAX_DB_FIELD];
00525 int counter = 0;
00526
00527 switch (cmd) {
00528 case CLI_INIT:
00529 e->command = "database showkey";
00530 e->usage =
00531 "Usage: database showkey <keytree>\n"
00532 " Shows Asterisk database contents, restricted to a given key.\n";
00533 return NULL;
00534 case CLI_GENERATE:
00535 return NULL;
00536 }
00537
00538 if (a->argc == 3) {
00539
00540 snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
00541 } else {
00542 return CLI_SHOWUSAGE;
00543 }
00544
00545 if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
00546 ast_cli(a->fd, "Database unavailable\n");
00547 return CLI_SUCCESS;
00548 }
00549
00550 ast_cli(a->fd, "%d results found.\n", counter);
00551 return CLI_SUCCESS;
00552 }
00553
00554 static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
00555 {
00556 struct ast_db_entry **ret = data;
00557 struct ast_db_entry *cur;
00558 const char *key_s = dbt_data2str_full(key, "<bad key>");
00559 const char *value_s = dbt_data2str_full(value, "<bad value>");
00560 size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
00561
00562 if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
00563 cur->next = *ret;
00564 cur->key = cur->data + value_slen;
00565 strcpy(cur->data, value_s);
00566 strcpy(cur->key, key_s);
00567 *ret = cur;
00568 return 1;
00569 }
00570
00571 return 0;
00572 }
00573
00574 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00575 {
00576 char prefix[MAX_DB_FIELD];
00577 struct ast_db_entry *ret = NULL;
00578
00579 if (!ast_strlen_zero(family)) {
00580 if (!ast_strlen_zero(keytree)) {
00581
00582 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00583 } else {
00584
00585 snprintf(prefix, sizeof(prefix), "/%s", family);
00586 }
00587 } else {
00588 prefix[0] = '\0';
00589 }
00590
00591 if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) {
00592 ast_log(LOG_WARNING, "Database unavailable\n");
00593 return NULL;
00594 }
00595
00596 return ret;
00597 }
00598
00599 void ast_db_freetree(struct ast_db_entry *dbe)
00600 {
00601 struct ast_db_entry *last;
00602 while (dbe) {
00603 last = dbe;
00604 dbe = dbe->next;
00605 ast_free(last);
00606 }
00607 }
00608
00609 static struct ast_cli_entry cli_database[] = {
00610 AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
00611 AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00612 AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
00613 AST_CLI_DEFINE(handle_cli_database_put, "Adds/updates database value"),
00614 AST_CLI_DEFINE(handle_cli_database_del, "Removes database key/value"),
00615 AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
00616 };
00617
00618 static int manager_dbput(struct mansession *s, const struct message *m)
00619 {
00620 const char *family = astman_get_header(m, "Family");
00621 const char *key = astman_get_header(m, "Key");
00622 const char *val = astman_get_header(m, "Val");
00623 int res;
00624
00625 if (ast_strlen_zero(family)) {
00626 astman_send_error(s, m, "No family specified");
00627 return 0;
00628 }
00629 if (ast_strlen_zero(key)) {
00630 astman_send_error(s, m, "No key specified");
00631 return 0;
00632 }
00633
00634 res = ast_db_put(family, key, S_OR(val, ""));
00635 if (res) {
00636 astman_send_error(s, m, "Failed to update entry");
00637 } else {
00638 astman_send_ack(s, m, "Updated database successfully");
00639 }
00640 return 0;
00641 }
00642
00643 static int manager_dbget(struct mansession *s, const struct message *m)
00644 {
00645 const char *id = astman_get_header(m,"ActionID");
00646 char idText[256] = "";
00647 const char *family = astman_get_header(m, "Family");
00648 const char *key = astman_get_header(m, "Key");
00649 char tmp[MAX_DB_FIELD];
00650 int res;
00651
00652 if (ast_strlen_zero(family)) {
00653 astman_send_error(s, m, "No family specified.");
00654 return 0;
00655 }
00656 if (ast_strlen_zero(key)) {
00657 astman_send_error(s, m, "No key specified.");
00658 return 0;
00659 }
00660
00661 if (!ast_strlen_zero(id))
00662 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00663
00664 res = ast_db_get(family, key, tmp, sizeof(tmp));
00665 if (res) {
00666 astman_send_error(s, m, "Database entry not found");
00667 } else {
00668 astman_send_ack(s, m, "Result will follow");
00669 astman_append(s, "Event: DBGetResponse\r\n"
00670 "Family: %s\r\n"
00671 "Key: %s\r\n"
00672 "Val: %s\r\n"
00673 "%s"
00674 "\r\n",
00675 family, key, tmp, idText);
00676 astman_append(s, "Event: DBGetComplete\r\n"
00677 "%s"
00678 "\r\n",
00679 idText);
00680 }
00681 return 0;
00682 }
00683
00684 static int manager_dbdel(struct mansession *s, const struct message *m)
00685 {
00686 const char *family = astman_get_header(m, "Family");
00687 const char *key = astman_get_header(m, "Key");
00688 int res;
00689
00690 if (ast_strlen_zero(family)) {
00691 astman_send_error(s, m, "No family specified.");
00692 return 0;
00693 }
00694
00695 if (ast_strlen_zero(key)) {
00696 astman_send_error(s, m, "No key specified.");
00697 return 0;
00698 }
00699
00700 res = ast_db_del(family, key);
00701 if (res)
00702 astman_send_error(s, m, "Database entry not found");
00703 else
00704 astman_send_ack(s, m, "Key deleted successfully");
00705
00706 return 0;
00707 }
00708
00709 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00710 {
00711 const char *family = astman_get_header(m, "Family");
00712 const char *key = astman_get_header(m, "Key");
00713 int res;
00714
00715 if (ast_strlen_zero(family)) {
00716 astman_send_error(s, m, "No family specified.");
00717 return 0;
00718 }
00719
00720 if (!ast_strlen_zero(key))
00721 res = ast_db_deltree(family, key);
00722 else
00723 res = ast_db_deltree(family, NULL);
00724
00725 if (res < 0)
00726 astman_send_error(s, m, "Database entry not found");
00727 else
00728 astman_send_ack(s, m, "Key tree deleted successfully");
00729
00730 return 0;
00731 }
00732
00733
00734
00735
00736
00737
00738
00739 static void db_sync(void)
00740 {
00741 ast_cond_signal(&dbcond);
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 static void *db_sync_thread(void *data)
00755 {
00756 ast_mutex_lock(&dblock);
00757 for (;;) {
00758 ast_cond_wait(&dbcond, &dblock);
00759 ast_mutex_unlock(&dblock);
00760 sleep(1);
00761 ast_mutex_lock(&dblock);
00762 astdb->sync(astdb, 0);
00763 }
00764
00765 return NULL;
00766 }
00767
00768 int astdb_init(void)
00769 {
00770 pthread_t dont_care;
00771
00772 ast_cond_init(&dbcond, NULL);
00773 if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) {
00774 return -1;
00775 }
00776
00777 dbinit();
00778 ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00779 ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00780 ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00781 ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00782 ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00783 return 0;
00784 }