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