aboutsummaryrefslogtreecommitdiffstats
path: root/pbx/pbx_dundi.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-10-29 13:04:37 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-10-29 13:04:37 +0000
commit477f21a9461a695f7266435cbb83250e69c88c02 (patch)
tree15dafcdd34402bb978a65742ee59bdcf97ed8189 /pbx/pbx_dundi.c
parentcc877d2d6e0e59d5cad15c49dc0f63663ccf4e1f (diff)
Complete DUNDi push (first pass) support
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4125 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'pbx/pbx_dundi.c')
-rwxr-xr-xpbx/pbx_dundi.c254
1 files changed, 212 insertions, 42 deletions
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index ed70de5d7..12a2335a3 100755
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -103,6 +103,7 @@ static struct io_context *io;
static struct sched_context *sched;
static int netsocket = -1;
static pthread_t netthreadid = AST_PTHREADT_NULL;
+static pthread_t precachethreadid = AST_PTHREADT_NULL;
static int tos = 0;
static int dundidebug = 0;
static int authdebug = 0;
@@ -145,6 +146,13 @@ struct dundi_hint_metadata {
char exten[AST_MAX_EXTENSION];
};
+struct dundi_precache_queue {
+ struct dundi_precache_queue *next;
+ char *context;
+ time_t expiration;
+ char number[0];
+};
+
struct dundi_request;
struct dundi_transaction {
@@ -244,7 +252,10 @@ static struct dundi_peer {
struct dundi_peer *next;
} *peers;
+static struct dundi_precache_queue *pcq;
+
AST_MUTEX_DEFINE_STATIC(peerlock);
+AST_MUTEX_DEFINE_STATIC(pclock);
static int dundi_xmit(struct dundi_packet *pack);
@@ -648,7 +659,6 @@ static void *dundi_precache_thread(void *data)
dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
ast_mutex_lock(&peerlock);
- ast_log(LOG_WARNING, "XXX We should schedule retransmission here XXX\n");
/* Truncate if "don't ask" isn't present */
if (!(hmd.flags & DUNDI_HINT_DONT_ASK))
hmd.exten[0] = '\0';
@@ -822,7 +832,7 @@ static int cache_save_hint(dundi_eid *eidpeer, struct dundi_request *req, struct
return 0;
}
-static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration)
+static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
{
int x;
char key1[256];
@@ -834,6 +844,14 @@ static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start,
if (expiration < 1)
expiration = DUNDI_DEFAULT_CACHE_TIME;
+
+ /* Keep pushes a little longer, cut pulls a little short */
+ if (push)
+ expiration += 10;
+ else
+ expiration -= 10;
+ if (expiration < 1)
+ expiration = 1;
dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
snprintf(key1, sizeof(key1), "%s/%s/%s/e%08lx", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
@@ -855,16 +873,6 @@ static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start,
return 0;
}
-static void dundi_precache_full(void)
-{
- struct dundi_mapping *cur;
- cur = mappings;
- while(cur) {
- ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
- cur = cur->next;
- }
-}
-
static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
{
struct dundi_query_state *st;
@@ -935,7 +943,7 @@ static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies
}
/* Save all the results (if any) we had. Even if no results, still cache lookup. */
- cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration);
+ cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
if (ies->hint)
cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
@@ -1670,7 +1678,7 @@ static int handle_command_response(struct dundi_transaction *trans, struct dundi
/* Save all the results (if any) we had. Even if no results, still cache lookup. Let
the cache know if this request was unaffected by our entity list. */
cache_save(&trans->them_eid, trans->parent, y,
- ies.hint ? ntohs(ies.hint->flags) & DUNDI_HINT_UNAFFECTED : 0, ies.expiration);
+ ies.hint ? ntohs(ies.hint->flags) & DUNDI_HINT_UNAFFECTED : 0, ies.expiration, 0);
if (ies.hint) {
cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration);
if (ntohs(ies.hint->flags) & DUNDI_HINT_TTL_EXPIRED)
@@ -2091,9 +2099,45 @@ static void *network_thread(void *ignore)
return NULL;
}
+static void *process_precache(void *ign)
+{
+ struct dundi_precache_queue *qe;
+ time_t now;
+ char context[256]="";
+ char number[256]="";
+ int run;
+ for (;;) {
+ time(&now);
+ run = 0;
+ ast_mutex_lock(&pclock);
+ if (pcq) {
+ if (!pcq->expiration) {
+ /* Gone... Remove... */
+ qe = pcq;
+ pcq = pcq->next;
+ free(qe);
+ } else if (pcq->expiration < now) {
+ /* Process this entry */
+ pcq->expiration = 0;
+ strncpy(context, pcq->context, sizeof(context) - 1);
+ strncpy(number, pcq->number, sizeof(number) - 1);
+ run = 1;
+ }
+ }
+ ast_mutex_unlock(&pclock);
+ if (run) {
+ dundi_precache(context, number);
+ } else
+ sleep(1);
+ }
+ return NULL;
+}
+
static int start_network_thread(void)
{
- return ast_pthread_create(&netthreadid, NULL, network_thread, NULL);
+ ast_pthread_create(&netthreadid, NULL, network_thread, NULL);
+ ast_pthread_create(&precachethreadid, NULL, process_precache, NULL);
+ return 0;
}
static int dundi_do_debug(int fd, int argc, char *argv[])
@@ -2551,6 +2595,33 @@ static int dundi_show_mappings(int fd, int argc, char *argv[])
#undef FORMAT2
}
+static int dundi_show_precache(int fd, int argc, char *argv[])
+{
+#define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
+#define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
+ struct dundi_precache_queue *qe;
+ int h,m,s;
+ time_t now;
+
+ if (argc != 3)
+ return RESULT_SHOWUSAGE;
+ time(&now);
+ ast_mutex_lock(&pclock);
+ ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
+ for (qe = pcq;qe;qe = qe->next) {
+ s = qe->expiration - now;
+ h = s / 3600;
+ s = s % 3600;
+ m = s / 60;
+ s = s % 60;
+ ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
+ }
+ ast_mutex_unlock(&pclock);
+ return RESULT_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
static char debug_usage[] =
"Usage: dundi debug\n"
" Enables dumping of DUNDi packets for debugging purposes\n";
@@ -2581,6 +2652,10 @@ static char show_mappings_usage[] =
"Usage: dundi show mappings\n"
" Lists all known DUNDi mappings.\n";
+static char show_precache_usage[] =
+"Usage: dundi show precache\n"
+" Lists all known DUNDi scheduled precache updates.\n";
+
static char show_entityid_usage[] =
"Usage: dundi show entityid\n"
" Displays the global entityid for this host.\n";
@@ -2644,6 +2719,9 @@ static struct ast_cli_entry cli_show_entityid =
static struct ast_cli_entry cli_show_mappings =
{ { "dundi", "show", "mappings", NULL }, dundi_show_mappings, "Show DUNDi mappings", show_mappings_usage };
+static struct ast_cli_entry cli_show_precache =
+ { { "dundi", "show", "precache", NULL }, dundi_show_precache, "Show DUNDi precache", show_precache_usage };
+
static struct ast_cli_entry cli_show_requests =
{ { "dundi", "show", "requests", NULL }, dundi_show_requests, "Show DUNDi requests", show_requests_usage };
@@ -3013,7 +3091,7 @@ static int dundi_discover(struct dundi_transaction *trans)
return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
}
-static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount)
+static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
{
struct dundi_ie_data ied;
int x, res;
@@ -3048,26 +3126,35 @@ static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping
}
}
- memset(&ied, 0, sizeof(ied));
- dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
- if (!dundi_eid_zero(&trans->us_eid))
- dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
- for (x=0;x<trans->eidcount;x++)
- dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
- dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
- dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
- dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
- for (x=0;x<ouranswers;x++) {
- /* Add answers */
- if (dr[x].expiration && (expiration > dr[x].expiration))
- expiration = dr[x].expiration;
- dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
+ if (ouranswers > 0) {
+ *foundanswers += ouranswers;
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
+ if (!dundi_eid_zero(&trans->us_eid))
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
+ for (x=0;x<trans->eidcount;x++)
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
+ dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
+ for (x=0;x<ouranswers;x++) {
+ /* Add answers */
+ if (dr[x].expiration && (expiration > dr[x].expiration))
+ expiration = dr[x].expiration;
+ dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
+ }
+ dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
+ dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
+ if (trans->autokilltimeout)
+ trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
+ if (expiration < *minexp)
+ *minexp = expiration;
+ return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
+ } else {
+ /* Oops, nothing to send... */
+ destroy_trans(trans, 0);
+ return 0;
}
- dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
- dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
- if (trans->autokilltimeout)
- trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
- return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
}
static int dundi_query(struct dundi_transaction *trans)
@@ -3103,12 +3190,12 @@ static int discover_transactions(struct dundi_request *dr)
return 0;
}
-static int precache_transactions(struct dundi_request *dr, struct dundi_mapping *maps, int mapcount)
+static int precache_transactions(struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
{
struct dundi_transaction *trans;
trans = dr->trans;
while(trans) {
- precache_trans(trans, maps, mapcount);
+ precache_trans(trans, maps, mapcount, expiration, foundanswers);
trans = trans->next;
}
return 0;
@@ -3497,6 +3584,78 @@ int dundi_lookup(struct dundi_result *result, int maxret, struct ast_channel *ch
return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
}
+static void reschedule_precache(const char *number, const char *context, int expiration)
+{
+ int len;
+ struct dundi_precache_queue *qe, *prev=NULL;
+ ast_mutex_lock(&pclock);
+ qe = pcq;
+ while(qe) {
+ if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
+ if (prev)
+ prev->next = qe->next;
+ else
+ pcq = qe->next;
+ qe->next = NULL;
+ break;
+ }
+ prev = qe;
+ qe = qe->next;
+ };
+ if (!qe) {
+ len = sizeof(struct dundi_precache_queue);
+ len += strlen(number + 1);
+ len += strlen(context + 1);
+ qe = malloc(len);
+ if (qe) {
+ memset(qe, 0, len);
+ strcpy(qe->number, number);
+ qe->context = qe->number + strlen(number) + 1;
+ strcpy(qe->context, context);
+ }
+ }
+ time(&qe->expiration);
+ qe->expiration += expiration;
+ prev = pcq;
+ if (prev) {
+ while(prev->next && (prev->next->expiration <= qe->expiration))
+ prev = prev->next;
+ qe->next = prev->next;
+ prev->next = qe;
+ } else
+ pcq = qe;
+ ast_mutex_unlock(&pclock);
+
+}
+
+static void dundi_precache_full(void)
+{
+ struct dundi_mapping *cur;
+ struct ast_context *con;
+ struct ast_exten *e;
+ cur = mappings;
+ while(cur) {
+ ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
+ ast_lock_contexts();
+ con = ast_walk_contexts(NULL);
+ while(con) {
+ if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
+ /* Found the match, now queue them all up */
+ ast_lock_context(con);
+ e = ast_walk_context_extensions(con, NULL);
+ while(e) {
+ reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
+ e = ast_walk_context_extensions(con, e);
+ }
+ ast_unlock_context(con);
+ }
+ con = ast_walk_contexts(con);
+ }
+ ast_unlock_contexts();
+ cur = cur->next;
+ }
+}
+
static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[])
{
struct dundi_request dr;
@@ -3505,6 +3664,7 @@ static int dundi_precache_internal(const char *context, const char *number, int
struct timeval start;
struct dundi_mapping *maps=NULL, *cur;
int nummaps;
+ int foundanswers;
int foundcache, skipped, ttlms, ms;
if (!context)
context = "e164";
@@ -3547,7 +3707,14 @@ static int dundi_precache_internal(const char *context, const char *number, int
dr.pfds[0] = dr.pfds[1] = -1;
build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
optimize_transactions(&dr, 0);
- precache_transactions(&dr, maps, nummaps);
+ foundanswers = 0;
+ precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
+ if (foundanswers) {
+ if (dr.expiration > 0)
+ reschedule_precache(dr.number, dr.dcontext, dr.expiration);
+ else
+ ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
+ }
gettimeofday(&start, NULL);
while(dr.trans && (calc_ms(&start) < ttlms)) {
if (dr.pfds[0] > -1) {
@@ -4081,11 +4248,11 @@ static void build_peer(dundi_eid *eid, struct ast_variable *v)
ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n",
dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
peer->dead = 1;
- } else if (peer->include && !(peer->model & DUNDI_MODEL_OUTBOUND)) {
- ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer!\n",
+ } else if (peer->include && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n",
dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
- } else if (peer->permit && !(peer->model & DUNDI_MODEL_INBOUND)) {
- ast_log(LOG_WARNING, "Peer '%s' is supposed to have permission for some inbound searches but isn't an inbound peer!\n",
+ } else if (peer->permit && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' is supposed to have permission for some inbound searches but isn't an inbound peer or outbound precache!\n",
dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
} else {
if (needregister) {
@@ -4353,6 +4520,7 @@ static int set_config(char *config_file, struct sockaddr_in* sin)
prune_peers();
ast_destroy(cfg);
load_password();
+ dundi_precache_full();
return 0;
}
@@ -4370,6 +4538,7 @@ int unload_module(void)
ast_cli_unregister(&cli_show_trans);
ast_cli_unregister(&cli_show_requests);
ast_cli_unregister(&cli_show_mappings);
+ ast_cli_unregister(&cli_show_precache);
ast_cli_unregister(&cli_show_peer);
ast_cli_unregister(&cli_lookup);
ast_cli_unregister(&cli_precache);
@@ -4421,6 +4590,7 @@ int load_module(void)
ast_cli_register(&cli_show_trans);
ast_cli_register(&cli_show_requests);
ast_cli_register(&cli_show_mappings);
+ ast_cli_register(&cli_show_precache);
ast_cli_register(&cli_show_peer);
ast_cli_register(&cli_lookup);
ast_cli_register(&cli_precache);