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: 345682 $")
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 " 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
00492 snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00493 } else if (a->argc == 3) {
00494
00495 snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00496 } else if (a->argc == 2) {
00497
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
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
00586 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00587 } else {
00588
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
00739
00740
00741
00742
00743 static void db_sync(void)
00744 {
00745 ast_cond_signal(&dbcond);
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
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 }