allow users of RTP to know when the peer endpoint is (apparently) behind a NAT
[asterisk/asterisk.git] / db.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 /* DB3 is licensed under Sleepycat Public License and is thus incompatible
15    with GPL.  To avoid having to make another exception (and complicate 
16    licensing even further) we elect to use DB1 which is BSD licensed */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/time.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <dirent.h>
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/channel.h"
32 #include "asterisk/file.h"
33 #include "asterisk/app.h"
34 #include "asterisk/dsp.h"
35 #include "asterisk/logger.h"
36 #include "asterisk/options.h"
37 #include "asterisk/astdb.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/manager.h"
42 #include "db1-ast/include/db.h"
43
44 static DB *astdb;
45 AST_MUTEX_DEFINE_STATIC(dblock);
46
47 static int dbinit(void) 
48 {
49         if (!astdb) {
50                 if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
51                         ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
52                 }
53         }
54         if (astdb)
55                 return 0;
56         return -1;
57 }
58
59
60 static inline int keymatch(const char *key, const char *prefix)
61 {
62         int preflen = strlen(prefix);
63         if (!preflen)
64                 return 1;
65         if (!strcasecmp(key, prefix))
66                 return 1;
67         if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
68                 if (key[preflen] == '/')
69                         return 1;
70         }
71         return 0;
72 }
73
74 static inline int subkeymatch(const char *key, const char *suffix)
75 {
76         int suffixlen = strlen(suffix);
77         if (suffixlen) {
78                 const char *subkey = key + strlen(key) - suffixlen;
79                 if (subkey < key)
80                         return 0;
81                 if (!strcasecmp(subkey, suffix))
82                         return 1;
83         }
84         return 0;
85 }
86
87 int ast_db_deltree(const char *family, const char *keytree)
88 {
89         char prefix[256];
90         DBT key, data;
91         char *keys;
92         int res;
93         int pass;
94         
95         if (family) {
96                 if (keytree) {
97                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
98                 } else {
99                         snprintf(prefix, sizeof(prefix), "/%s", family);
100                 }
101         } else if (keytree) {
102                 return -1;
103         } else {
104                 prefix[0] = '\0';
105         }
106         
107         ast_mutex_lock(&dblock);
108         if (dbinit()) 
109                 return -1;
110         
111         memset(&key, 0, sizeof(key));
112         memset(&data, 0, sizeof(data));
113         pass = 0;
114         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
115                 if (key.size) {
116                         keys = key.data;
117                         keys[key.size - 1] = '\0';
118                 } else {
119                         keys = "<bad key>";
120                 }
121                 if (keymatch(keys, prefix)) {
122                         astdb->del(astdb, &key, 0);
123                 }
124         }
125         astdb->sync(astdb, 0);
126         ast_mutex_unlock(&dblock);
127         return 0;
128 }
129
130 int ast_db_put(const char *family, const char *keys, char *value)
131 {
132         char fullkey[256];
133         DBT key, data;
134         int res, fullkeylen;
135
136         ast_mutex_lock(&dblock);
137         if (dbinit()) {
138                 ast_mutex_unlock(&dblock);
139                 return -1;
140         }
141
142         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
143         memset(&key, 0, sizeof(key));
144         memset(&data, 0, sizeof(data));
145         key.data = fullkey;
146         key.size = fullkeylen + 1;
147         data.data = value;
148         data.size = strlen(value) + 1;
149         res = astdb->put(astdb, &key, &data, 0);
150         astdb->sync(astdb, 0);
151         ast_mutex_unlock(&dblock);
152         if (res)
153                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
154         return res;
155 }
156
157 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
158 {
159         char fullkey[256] = "";
160         DBT key, data;
161         int res, fullkeylen;
162
163         ast_mutex_lock(&dblock);
164         if (dbinit()) {
165                 ast_mutex_unlock(&dblock);
166                 return -1;
167         }
168
169         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
170         memset(&key, 0, sizeof(key));
171         memset(&data, 0, sizeof(data));
172         memset(value, 0, valuelen);
173         key.data = fullkey;
174         key.size = fullkeylen + 1;
175         
176         res = astdb->get(astdb, &key, &data, 0);
177         
178         ast_mutex_unlock(&dblock);
179
180         /* Be sure to NULL terminate our data either way */
181         if (res) {
182                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
183         } else {
184 #if 0
185                 printf("Got value of size %d\n", data.size);
186 #endif
187                 if (data.size) {
188                         ((char *)data.data)[data.size - 1] = '\0';
189                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
190                         strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
191                         value[valuelen - 1] = '\0';
192                 } else {
193                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
194                 }
195         }
196         return res;
197 }
198
199 int ast_db_del(const char *family, const char *keys)
200 {
201         char fullkey[256];
202         DBT key;
203         int res, fullkeylen;
204
205         ast_mutex_lock(&dblock);
206         if (dbinit()) {
207                 ast_mutex_unlock(&dblock);
208                 return -1;
209         }
210         
211         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
212         memset(&key, 0, sizeof(key));
213         key.data = fullkey;
214         key.size = fullkeylen + 1;
215         
216         res = astdb->del(astdb, &key, 0);
217         astdb->sync(astdb, 0);
218         
219         ast_mutex_unlock(&dblock);
220
221         if (res) 
222                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
223         return res;
224 }
225
226 static int database_put(int fd, int argc, char *argv[])
227 {
228         int res;
229         if (argc != 5)
230                 return RESULT_SHOWUSAGE;
231         res = ast_db_put(argv[2], argv[3], argv[4]);
232         if (res)  {
233                 ast_cli(fd, "Failed to update entry\n");
234         } else {
235                 ast_cli(fd, "Updated database successfully\n");
236         }
237         return RESULT_SUCCESS;
238 }
239
240 static int database_get(int fd, int argc, char *argv[])
241 {
242         int res;
243         char tmp[256];
244         if (argc != 4)
245                 return RESULT_SHOWUSAGE;
246         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
247         if (res) {
248                 ast_cli(fd, "Database entry not found.\n");
249         } else {
250                 ast_cli(fd, "Value: %s\n", tmp);
251         }
252         return RESULT_SUCCESS;
253 }
254
255 static int database_del(int fd, int argc, char *argv[])
256 {
257         int res;
258         if (argc != 4)
259                 return RESULT_SHOWUSAGE;
260         res = ast_db_del(argv[2], argv[3]);
261         if (res) {
262                 ast_cli(fd, "Database entry does not exist.\n");
263         } else {
264                 ast_cli(fd, "Database entry removed.\n");
265         }
266         return RESULT_SUCCESS;
267 }
268
269 static int database_deltree(int fd, int argc, char *argv[])
270 {
271         int res;
272         if ((argc < 3) || (argc > 4))
273                 return RESULT_SHOWUSAGE;
274         if (argc == 4) {
275                 res = ast_db_deltree(argv[2], argv[3]);
276         } else {
277                 res = ast_db_deltree(argv[2], NULL);
278         }
279         if (res) {
280                 ast_cli(fd, "Database entries do not exist.\n");
281         } else {
282                 ast_cli(fd, "Database entries removed.\n");
283         }
284         return RESULT_SUCCESS;
285 }
286
287 static int database_show(int fd, int argc, char *argv[])
288 {
289         char prefix[256];
290         DBT key, data;
291         char *keys, *values;
292         int res;
293         int pass;
294
295         if (argc == 4) {
296                 /* Family and key tree */
297                 snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
298         } else if (argc == 3) {
299                 /* Family only */
300                 snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
301         } else if (argc == 2) {
302                 /* Neither */
303                 prefix[0] = '\0';
304         } else {
305                 return RESULT_SHOWUSAGE;
306         }
307         ast_mutex_lock(&dblock);
308         if (dbinit()) {
309                 ast_mutex_unlock(&dblock);
310                 ast_cli(fd, "Database unavailable\n");
311                 return RESULT_SUCCESS;  
312         }
313         memset(&key, 0, sizeof(key));
314         memset(&data, 0, sizeof(data));
315         pass = 0;
316         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
317                 if (key.size) {
318                         keys = key.data;
319                         keys[key.size - 1] = '\0';
320                 } else {
321                         keys = "<bad key>";
322                 }
323                 if (data.size) {
324                         values = data.data;
325                         values[data.size - 1]='\0';
326                 } else {
327                         values = "<bad value>";
328                 }
329                 if (keymatch(keys, prefix)) {
330                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
331                 }
332         }
333         ast_mutex_unlock(&dblock);
334         return RESULT_SUCCESS;  
335 }
336
337 static int database_showkey(int fd, int argc, char *argv[])
338 {
339         char suffix[256];
340         DBT key, data;
341         char *keys, *values;
342         int res;
343         int pass;
344
345         if (argc == 3) {
346                 /* Key only */
347                 snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
348         } else {
349                 return RESULT_SHOWUSAGE;
350         }
351         ast_mutex_lock(&dblock);
352         if (dbinit()) {
353                 ast_mutex_unlock(&dblock);
354                 ast_cli(fd, "Database unavailable\n");
355                 return RESULT_SUCCESS;  
356         }
357         memset(&key, 0, sizeof(key));
358         memset(&data, 0, sizeof(data));
359         pass = 0;
360         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
361                 if (key.size) {
362                         keys = key.data;
363                         keys[key.size - 1] = '\0';
364                 } else {
365                         keys = "<bad key>";
366                 }
367                 if (data.size) {
368                         values = data.data;
369                         values[data.size - 1]='\0';
370                 } else {
371                         values = "<bad value>";
372                 }
373                 if (subkeymatch(keys, suffix)) {
374                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
375                 }
376         }
377         ast_mutex_unlock(&dblock);
378         return RESULT_SUCCESS;  
379 }
380
381 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
382 {
383         char prefix[256];
384         DBT key, data;
385         char *keys, *values;
386         int res;
387         int pass;
388         struct ast_db_entry *last = NULL;
389         struct ast_db_entry *cur, *ret=NULL;
390
391         if (family && !ast_strlen_zero(family)) {
392                 if (keytree && !ast_strlen_zero(keytree)) {
393                         /* Family and key tree */
394                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
395                 } else {
396                         /* Family only */
397                         snprintf(prefix, sizeof(prefix), "/%s", family);
398                 }
399         } else {
400                 prefix[0] = '\0';
401         }
402         ast_mutex_lock(&dblock);
403         if (dbinit()) {
404                 ast_mutex_unlock(&dblock);
405                 ast_log(LOG_WARNING, "Database unavailable\n");
406                 return NULL;    
407         }
408         memset(&key, 0, sizeof(key));
409         memset(&data, 0, sizeof(data));
410         pass = 0;
411         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
412                 if (key.size) {
413                         keys = key.data;
414                         keys[key.size - 1] = '\0';
415                 } else {
416                         keys = "<bad key>";
417                 }
418                 if (data.size) {
419                         values = data.data;
420                         values[data.size - 1] = '\0';
421                 } else {
422                         values = "<bad value>";
423                 }
424                 if (keymatch(keys, prefix)) {
425                         cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
426                         if (cur) {
427                                 cur->next = NULL;
428                                 cur->key = cur->data + strlen(values) + 1;
429                                 strcpy(cur->data, values);
430                                 strcpy(cur->key, keys);
431                                 if (last) {
432                                         last->next = cur;
433                                 } else {
434                                         ret = cur;
435                                 }
436                                 last = cur;
437                         }
438                 }
439         }
440         ast_mutex_unlock(&dblock);
441         return ret;     
442 }
443
444 void ast_db_freetree(struct ast_db_entry *dbe)
445 {
446         struct ast_db_entry *last;
447         while (dbe) {
448                 last = dbe;
449                 dbe = dbe->next;
450                 free(last);
451         }
452 }
453
454 static char database_show_usage[] =
455 "Usage: database show [family [keytree]]\n"
456 "       Shows Asterisk database contents, optionally restricted\n"
457 "to a given family, or family and keytree.\n";
458
459 static char database_showkey_usage[] =
460 "Usage: database showkey <keytree>\n"
461 "       Shows Asterisk database contents, restricted to a given key.\n";
462
463 static char database_put_usage[] =
464 "Usage: database put <family> <key> <value>\n"
465 "       Adds or updates an entry in the Asterisk database for\n"
466 "a given family, key, and value.\n";
467
468 static char database_get_usage[] =
469 "Usage: database get <family> <key>\n"
470 "       Retrieves an entry in the Asterisk database for a given\n"
471 "family and key.\n";
472
473 static char database_del_usage[] =
474 "Usage: database del <family> <key>\n"
475 "       Deletes an entry in the Asterisk database for a given\n"
476 "family and key.\n";
477
478 static char database_deltree_usage[] =
479 "Usage: database deltree <family> [keytree]\n"
480 "       Deletes a family or specific keytree within a family\n"
481 "in the Asterisk database.\n";
482
483 struct ast_cli_entry cli_database_show =
484 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
485
486 struct ast_cli_entry cli_database_showkey =
487 { { "database", "showkey", NULL }, database_showkey, "Shows database contents", database_showkey_usage };
488
489 struct ast_cli_entry cli_database_get =
490 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
491
492 struct ast_cli_entry cli_database_put =
493 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
494
495 struct ast_cli_entry cli_database_del =
496 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
497
498 struct ast_cli_entry cli_database_deltree =
499 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
500
501 static int manager_dbput(struct mansession *s, struct message *m)
502 {
503         char *family = astman_get_header(m, "Family");
504         char *key = astman_get_header(m, "Key");
505         char *val = astman_get_header(m, "Val");
506         int res;
507
508         if (!strlen(family)) {
509                 astman_send_error(s, m, "No family specified");
510                 return 0;
511         }
512         if (!strlen(key)) {
513                 astman_send_error(s, m, "No key specified");
514                 return 0;
515         }
516         if (!strlen(val)) {
517                 astman_send_error(s, m, "No val specified");
518                 return 0;
519         }
520
521         res = ast_db_put(family, key, val);
522         if (res) {
523                 astman_send_error(s, m, "Failed to update entry");
524         } else {
525                 astman_send_ack(s, m, "Updated database successfully");
526         }
527         return 0;
528 }
529
530 static int manager_dbget(struct mansession *s, struct message *m)
531 {
532         char *id = astman_get_header(m,"ActionID");
533         char idText[256] = "";
534         char *family = astman_get_header(m, "Family");
535         char *key = astman_get_header(m, "Key");
536         char tmp[256];
537         int res;
538
539         if (!strlen(family)) {
540                 astman_send_error(s, m, "No family specified.");
541                 return 0;
542         }
543         if (!strlen(key)) {
544                 astman_send_error(s, m, "No key specified.");
545                 return 0;
546         }
547
548         if (id && !ast_strlen_zero(id))
549                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
550
551         res = ast_db_get(family, key, tmp, sizeof(tmp));
552         if (res) {
553                 astman_send_error(s, m, "Database entry not found");
554         } else {
555                 astman_send_ack(s, m, "Result will follow");
556                 ast_mutex_lock(&s->lock);
557                 ast_cli(s->fd, "Event: DBGetResponse\r\n"
558                                 "Family: %s\r\n"
559                                 "Key: %s\r\n"
560                                 "Val: %s\r\n"
561                                 "%s"
562                                 "\r\n",
563                                 family, key, tmp, idText);
564                 ast_mutex_unlock(&s->lock);
565         }
566         return 0;
567 }
568
569 int astdb_init(void)
570 {
571         dbinit();
572         ast_cli_register(&cli_database_show);
573         ast_cli_register(&cli_database_showkey);
574         ast_cli_register(&cli_database_get);
575         ast_cli_register(&cli_database_put);
576         ast_cli_register(&cli_database_del);
577         ast_cli_register(&cli_database_deltree);
578         ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
579         ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
580         return 0;
581 }