Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:41 2007

Asterisk developer's documentation :: Codename Pineapple


pbx_dundi.c File Reference


Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <zlib.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/md5.h"
#include "asterisk/dundi.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/aes.h"
#include "dundi-parser.h"

Include dependency graph for pbx_dundi.c:

Go to the source code of this file.

Data Structures

struct  dundi_hint_metadata
struct  dundi_mapping
struct  dundi_packet
struct  dundi_peer
struct  dundi_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_transaction
struct  permission

Defines

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)
#define DUNDI_MODEL_INBOUND   (1 << 0)
#define DUNDI_MODEL_OUTBOUND   (1 << 1)
#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME
#define DUNDI_TIMING_HISTORY   10
#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
#define FORMAT   "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
#define FORMAT   "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64

Enumerations

enum  {
  FLAG_ISREG = (1 << 0), FLAG_DEAD = (1 << 1), FLAG_FINAL = (1 << 2), FLAG_ISQUAL = (1 << 3),
  FLAG_ENCRYPT = (1 << 4), FLAG_SENDFULLKEY = (1 << 5), FLAG_STOREHIST = (1 << 6)
}

Functions

static void abort_request (struct dundi_request *dr)
static int ack_trans (struct dundi_transaction *trans, int iseqno)
static void append_permission (struct permissionlist *permlist, char *s, int allow)
static int append_transaction (struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
static void apply_peer (struct dundi_transaction *trans, struct dundi_peer *p)
static AST_LIST_HEAD_NOLOCK_STATIC (alltrans, dundi_transaction)
static AST_LIST_HEAD_NOLOCK_STATIC (requests, dundi_request)
static AST_LIST_HEAD_NOLOCK_STATIC (mappings, dundi_mapping)
static AST_LIST_HEAD_STATIC (pcq, dundi_precache_queue)
static AST_LIST_HEAD_STATIC (peers, dundi_peer)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Distributed Universal Number Discovery (DUNDi)",.load=load_module,.unload=unload_module,.reload=reload,)
static unsigned long avoid_crc32 (dundi_eid *avoid[])
static void build_iv (unsigned char *iv)
static void build_mapping (char *name, char *value)
static void build_peer (dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
static void build_secret (char *secret, int seclen)
static void build_transactions (struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
static int cache_lookup (struct dundi_request *req, dundi_eid *peer_eid, unsigned long crc32, int *lowexpiration)
static int cache_lookup_internal (time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
static int cache_save (dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
static int cache_save_hint (dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
static void cancel_request (struct dundi_request *dr)
static int check_key (struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, unsigned long keycrc32)
static void check_password (void)
static int check_request (struct dundi_request *dr)
static char * complete_peer_4 (const char *line, const char *word, int pos, int state)
static char * complete_peer_helper (const char *line, const char *word, int pos, int state, int rpos)
static struct dundi_transactioncreate_transaction (struct dundi_peer *p)
static int decrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_decrypt_ctx *dcx)
static void destroy_map (struct dundi_mapping *map)
static void destroy_packet (struct dundi_packet *pack, int needfree)
static void destroy_packets (struct packetlist *p)
static void destroy_peer (struct dundi_peer *peer)
static void destroy_permissions (struct permissionlist *permlist)
static void destroy_trans (struct dundi_transaction *trans, int fromtimeout)
static int discover_transactions (struct dundi_request *dr)
static int do_autokill (void *data)
static int do_qualify (void *data)
static int do_register (void *data)
static int do_register_expire (void *data)
static int dundi_ack (struct dundi_transaction *trans, int final)
static int dundi_answer_entity (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_answer_query (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static void dundi_debug_output (const char *data)
static struct dundi_hdrdundi_decrypt (struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
static int dundi_discover (struct dundi_transaction *trans)
static int dundi_do_debug (int fd, int argc, char *argv[])
static int dundi_do_lookup (int fd, int argc, char *argv[])
static int dundi_do_precache (int fd, int argc, char *argv[])
static int dundi_do_query (int fd, int argc, char *argv[])
static int dundi_do_store_history (int fd, int argc, char *argv[])
static int dundi_encrypt (struct dundi_transaction *trans, struct dundi_packet *pack)
static void dundi_error_output (const char *data)
static int dundi_exec (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_flush (int fd, int argc, char *argv[])
static int dundi_helper (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag)
static void dundi_ie_append_eid_appropriately (struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us)
int dundi_lookup (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass)
 Lookup the given number in the given dundi context (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified. returns the number of results found or -1 on a hangup of teh channel.
static int dundi_lookup_internal (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[])
static int dundi_lookup_local (struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
static void * dundi_lookup_thread (void *data)
static int dundi_matchmore (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_no_debug (int fd, int argc, char *argv[])
static int dundi_no_store_history (int fd, int argc, char *argv[])
int dundi_precache (const char *context, const char *number)
 Pre-cache to push upstream peers.
static void dundi_precache_full (void)
static int dundi_precache_internal (const char *context, const char *number, int ttl, dundi_eid *avoids[])
static void * dundi_precache_thread (void *data)
static int dundi_prop_precache (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_query (struct dundi_transaction *trans)
int dundi_query_eid (struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid)
 Retrieve information on a specific EID.
static int dundi_query_eid_internal (struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[])
static void * dundi_query_thread (void *data)
static void dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin)
static int dundi_rexmit (void *data)
static int dundi_send (struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
static int dundi_show_entityid (int fd, int argc, char *argv[])
static int dundi_show_mappings (int fd, int argc, char *argv[])
static int dundi_show_peer (int fd, int argc, char *argv[])
static int dundi_show_peers (int fd, int argc, char *argv[])
static int dundi_show_precache (int fd, int argc, char *argv[])
static int dundi_show_requests (int fd, int argc, char *argv[])
static int dundi_show_trans (int fd, int argc, char *argv[])
static int dundi_xmit (struct dundi_packet *pack)
static int dundifunc_read (struct ast_channel *chan, const char *cmd, char *num, char *buf, size_t len)
static int encrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_encrypt_ctx *ecx)
static struct dundi_peerfind_peer (dundi_eid *eid)
static struct dundi_transactionfind_transaction (struct dundi_hdr *hdr, struct sockaddr_in *sin)
static int get_trans_id (void)
static int handle_command_response (struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
static int handle_frame (struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)
static int has_permission (struct permissionlist *permlist, char *cont)
static int load_module (void)
static void load_password (void)
static void mark_mappings (void)
static void mark_peers (void)
static char * model2str (int model)
static void * network_thread (void *ignore)
static int optimize_transactions (struct dundi_request *dr, int order)
static void populate_addr (struct dundi_peer *peer, dundi_eid *eid)
static int precache_trans (struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
static int precache_transactions (struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
static void * process_precache (void *ign)
static void prune_mappings (void)
static void prune_peers (void)
static void qualify_peer (struct dundi_peer *peer, int schedonly)
static int query_transactions (struct dundi_request *dr)
static int register_request (struct dundi_request *dr, struct dundi_request **pending)
static int reload (void)
static void reschedule_precache (const char *number, const char *context, int expiration)
static int rescomp (const void *a, const void *b)
static void reset_global_eid (void)
static int reset_transaction (struct dundi_transaction *trans)
static void save_secret (const char *newkey, const char *oldkey)
static int set_config (char *config_file, struct sockaddr_in *sin)
static int socket_read (int *id, int fd, short events, void *cbdata)
static void sort_results (struct dundi_result *results, int count)
static int start_network_thread (void)
static int str2tech (char *str)
static char * tech2str (int tech)
static int unload_module (void)
static void unregister_request (struct dundi_request *dr)
static int update_key (struct dundi_peer *peer)

Variables

static int authdebug = 0
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
static const char debug_usage []
static int default_expiration = 60
static char dept [80]
static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME
static struct ast_custom_function dundi_function
static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE
static struct ast_switch dundi_switch
static int dundi_ttl = DUNDI_DEFAULT_TTL
static int dundidebug = 0
static char email [80]
static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }
static const char flush_usage []
static int global_autokilltimeout = 0
static dundi_eid global_eid
static int global_storehistory = 0
static struct io_contextio
static char ipaddr [80]
static char locality [80]
static const char lookup_usage []
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static const char no_debug_usage []
static const char no_store_history_usage []
static char org [80]
static char phone [80]
static const char precache_usage []
static pthread_t precachethreadid = AST_PTHREADT_NULL
static const char query_usage []
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static const char show_entityid_usage []
static const char show_mappings_usage []
static const char show_peer_usage []
static const char show_peers_usage []
static const char show_precache_usage []
static const char show_requests_usage []
static const char show_trans_usage []
static char stateprov [80]
static const char store_history_usage []
static int tos = 0


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)
 

Definition at line 99 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)
 

Definition at line 82 of file pbx_dundi.c.

Referenced by dundi_show_peer(), handle_command_response(), and model2str().

#define DUNDI_MODEL_OUTBOUND   (1 << 1)
 

Definition at line 83 of file pbx_dundi.c.

Referenced by build_transactions(), dundi_show_peer(), model2str(), and set_config().

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
 

Definition at line 84 of file pbx_dundi.c.

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME
 

Definition at line 104 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10
 

Keep times of last 10 lookups

Definition at line 87 of file pbx_dundi.c.

Referenced by destroy_trans(), dundi_flush(), and dundi_show_peer().

#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
 

#define FORMAT   "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
 

#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
 

#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
 

#define FORMAT   "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
 

#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
 

#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
 

#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
 

#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
 

#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
 

#define MAX_OPTS   128
 

Definition at line 3914 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192
 

Definition at line 80 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64
 

Definition at line 78 of file pbx_dundi.c.

Referenced by dundi_do_lookup(), dundi_exec(), dundi_helper(), dundi_lookup_thread(), dundi_precache_internal(), dundi_prop_precache(), dundifunc_read(), and precache_trans().


Enumeration Type Documentation

anonymous enum
 

Enumerator:
FLAG_ISREG  Transaction is register request
FLAG_DEAD  Transaction is dead
FLAG_FINAL  Transaction has final message sent
FLAG_ISQUAL  Transaction is a qualification
FLAG_ENCRYPT  Transaction is encrypted wiht ECX/DCX
FLAG_SENDFULLKEY  Send full key on transaction
FLAG_STOREHIST  Record historic performance

Definition at line 89 of file pbx_dundi.c.

00089      {
00090    FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
00091    FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
00092    FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
00093    FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
00094    FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
00095    FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
00096    FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
00097 };


Function Documentation

static void abort_request struct dundi_request dr  )  [static]
 

Definition at line 3311 of file pbx_dundi.c.

References AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, destroy_trans(), and dr.

Referenced by dundi_lookup_internal().

03312 {
03313    struct dundi_transaction *trans;
03314 
03315    AST_LIST_LOCK(&peers);
03316    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03317       /* This will remove the transaction from the list */
03318       destroy_trans(trans, 0);
03319    }
03320    AST_LIST_UNLOCK(&peers);
03321 }

static int ack_trans struct dundi_transaction trans,
int  iseqno
[static]
 

Definition at line 1914 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_sched_del(), dundi_transaction::autokillid, destroy_packet(), destroy_packets(), LOG_WARNING, and sched.

Referenced by handle_frame().

01915 {
01916    struct dundi_packet *pack;
01917 
01918    /* Ack transmitted packet corresponding to iseqno */
01919    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01920       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01921          destroy_packet(pack, 0);
01922          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01923             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01924             destroy_packets(&trans->lasttrans);
01925          }
01926          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01927          if (trans->autokillid > -1)
01928             ast_sched_del(sched, trans->autokillid);
01929          trans->autokillid = -1;
01930          return 1;
01931       }
01932    }
01933 
01934    return 0;
01935 }

static void append_permission struct permissionlist *  permlist,
char *  s,
int  allow
[static]
 

Definition at line 3901 of file pbx_dundi.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

03902 {
03903    struct permission *perm;
03904 
03905    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03906       return;
03907 
03908    strcpy(perm->name, s);
03909    perm->allow = allow;
03910 
03911    AST_LIST_INSERT_TAIL(permlist, perm, list);
03912 }

static int append_transaction struct dundi_request dr,
struct dundi_peer p,
int  ttl,
dundi_eid avoid[]
[static]
 

Definition at line 3264 of file pbx_dundi.c.

References dundi_peer::addr, AST_LIST_INSERT_HEAD, ast_log(), ast_strlen_zero(), create_transaction(), dr, dundi_eid_to_str(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, option_debug, and dundi_transaction::ttl.

Referenced by build_transactions().

03265 {
03266    struct dundi_transaction *trans;
03267    int x;
03268    char eid_str[20];
03269    char eid_str2[20];
03270 
03271    /* Ignore if not registered */
03272    if (!p->addr.sin_addr.s_addr)
03273       return 0;
03274    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03275       return 0;
03276 
03277    if (option_debug) {
03278       if (ast_strlen_zero(dr->number))
03279          ast_log(LOG_DEBUG, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
03280       else
03281          ast_log(LOG_DEBUG, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
03282    }
03283 
03284    trans = create_transaction(p);
03285    if (!trans)
03286       return -1;
03287    trans->parent = dr;
03288    trans->ttl = ttl;
03289    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03290       trans->eids[x] = *avoid[x];
03291    trans->eidcount = x;
03292    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03293    
03294    return 0;
03295 }

static void apply_peer struct dundi_transaction trans,
struct dundi_peer p
[static]
 

Definition at line 1247 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, ast_set_flag, ast_strlen_zero(), dundi_transaction::autokilltimeout, DUNDI_DEFAULT_RETRANS_TIMER, dundi_peer::eid, FLAG_ENCRYPT, dundi_transaction::retranstimer, dundi_transaction::them_eid, and dundi_transaction::us_eid.

Referenced by create_transaction().

01248 {
01249    if (!trans->addr.sin_addr.s_addr)
01250       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01251    trans->us_eid = p->us_eid;
01252    trans->them_eid = p->eid;
01253    /* Enable encryption if appropriate */
01254    if (!ast_strlen_zero(p->inkey))
01255       ast_set_flag(trans, FLAG_ENCRYPT);  
01256    if (p->maxms) {
01257       trans->autokilltimeout = p->maxms;
01258       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01259       if (p->lastms > 1) {
01260          trans->retranstimer = p->lastms * 2;
01261          /* Keep it from being silly */
01262          if (trans->retranstimer < 150)
01263             trans->retranstimer = 150;
01264       }
01265       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01266          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01267    } else
01268       trans->autokilltimeout = global_autokilltimeout;
01269 }

static AST_LIST_HEAD_NOLOCK_STATIC alltrans  ,
dundi_transaction 
[static]
 

static AST_LIST_HEAD_NOLOCK_STATIC requests  ,
dundi_request 
[static]
 

static AST_LIST_HEAD_NOLOCK_STATIC mappings  ,
dundi_mapping 
[static]
 

static AST_LIST_HEAD_STATIC pcq  ,
dundi_precache_queue 
[static]
 

static AST_LIST_HEAD_STATIC peers  ,
dundi_peer 
[static]
 

AST_MODULE_INFO ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Distributed Universal Number Discovery (DUNDi)"  ,
load = load_module,
unload = unload_module,
reload = reload
 

static unsigned long avoid_crc32 dundi_eid avoid[]  )  [static]
 

Definition at line 3436 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03437 {
03438    /* Idea is that we're calculating a checksum which is independent of
03439       the order that the EID's are listed in */
03440    unsigned long acrc32 = 0;
03441    int x;
03442    for (x=0;avoid[x];x++) {
03443       /* Order doesn't matter */
03444       if (avoid[x+1]) {
03445          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03446       }
03447    }
03448    return acrc32;
03449 }

static void build_iv unsigned char *  iv  )  [static]
 

Definition at line 488 of file pbx_dundi.c.

References ast_random().

Referenced by build_secret(), dundi_encrypt(), and update_key().

00489 {
00490    /* XXX Would be nice to be more random XXX */
00491    unsigned int *fluffy;
00492    int x;
00493    fluffy = (unsigned int *)(iv);
00494    for (x=0;x<4;x++)
00495       fluffy[x] = ast_random();
00496 }

static void build_mapping char *  name,
char *  value
[static]
 

Definition at line 3916 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, ast_strlen_zero(), DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, LOG_WARNING, map, MAX_OPTS, and str2tech().

Referenced by set_config().

03917 {
03918    char *t, *fields[MAX_OPTS];
03919    struct dundi_mapping *map;
03920    int x;
03921    int y;
03922 
03923    t = ast_strdupa(value);
03924       
03925    AST_LIST_TRAVERSE(&mappings, map, list) {
03926       /* Find a double match */
03927       if (!strcasecmp(map->dcontext, name) && 
03928          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
03929            (!value[strlen(map->lcontext)] || 
03930             (value[strlen(map->lcontext)] == ','))))
03931          break;
03932    }
03933    if (!map) {
03934       if (!(map = ast_calloc(1, sizeof(*map))))
03935          return;
03936       AST_LIST_INSERT_HEAD(&mappings, map, list);
03937       map->dead = 1;
03938    }
03939    map->options = 0;
03940    memset(fields, 0, sizeof(fields));
03941    x = 0;
03942    while (t && x < MAX_OPTS) {
03943       fields[x++] = t;
03944       t = strchr(t, ',');
03945       if (t) {
03946          *t = '\0';
03947          t++;
03948       }
03949    } /* Russell was here, arrrr! */
03950    if ((x == 1) && ast_strlen_zero(fields[0])) {
03951       /* Placeholder mapping */
03952       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
03953       map->dead = 0;
03954    } else if (x >= 4) {
03955       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
03956       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
03957       if ((sscanf(fields[1], "%d", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) {
03958          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
03959          if ((map->tech = str2tech(fields[2]))) {
03960             map->dead = 0;
03961          }
03962       } else {
03963          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
03964       }
03965       for (y = 4;y < x; y++) {
03966          if (!strcasecmp(fields[y], "nounsolicited"))
03967             map->options |= DUNDI_FLAG_NOUNSOLICITED;
03968          else if (!strcasecmp(fields[y], "nocomunsolicit"))
03969             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
03970          else if (!strcasecmp(fields[y], "residential"))
03971             map->options |= DUNDI_FLAG_RESIDENTIAL;
03972          else if (!strcasecmp(fields[y], "commercial"))
03973             map->options |= DUNDI_FLAG_COMMERCIAL;
03974          else if (!strcasecmp(fields[y], "mobile"))
03975             map->options |= DUNDI_FLAG_MOBILE;
03976          else if (!strcasecmp(fields[y], "nopartial"))
03977             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
03978          else
03979             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
03980       }
03981    } else 
03982       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
03983 }

static void build_peer dundi_eid eid,
struct ast_variable v,
int *  globalpcmode
[static]
 

Definition at line 4071 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_sched_del(), destroy_permissions(), dundi_eid_cmp(), DUNDI_PORT, dundi_peer::eid, global_eid, hp, ast_variable::name, ast_variable::next, populate_addr(), sched, and ast_variable::value.

04072 {
04073    struct dundi_peer *peer;
04074    struct ast_hostent he;
04075    struct hostent *hp;
04076    dundi_eid testeid;
04077    int needregister=0;
04078    char eid_str[20];
04079 
04080    AST_LIST_LOCK(&peers);
04081    AST_LIST_TRAVERSE(&peers, peer, list) {
04082       if (!dundi_eid_cmp(&peer->eid, eid)) { 
04083          break;
04084       }
04085    }
04086    if (!peer) {
04087       /* Add us into the list */
04088       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04089          AST_LIST_UNLOCK(&peers);
04090          return;
04091       }
04092       peer->registerid = -1;
04093       peer->registerexpire = -1;
04094       peer->qualifyid = -1;
04095       peer->addr.sin_family = AF_INET;
04096       peer->addr.sin_port = htons(DUNDI_PORT);
04097       populate_addr(peer, eid);
04098       AST_LIST_INSERT_HEAD(&peers, peer, list);
04099    }
04100    peer->dead = 0;
04101    peer->eid = *eid;
04102    peer->us_eid = global_eid;
04103    destroy_permissions(&peer->permit);
04104    destroy_permissions(&peer->include);
04105    if (peer->registerid > -1)
04106       ast_sched_del(sched, peer->registerid);
04107    peer->registerid = -1;
04108    for (; v; v = v->next) {
04109       if (!strcasecmp(v->name, "inkey")) {
04110          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04111       } else if (!strcasecmp(v->name, "outkey")) {
04112          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04113       } else if (!strcasecmp(v->name, "host")) {
04114          if (!strcasecmp(v->value, "dynamic")) {
04115             peer->dynamic = 1;
04116          } else {
04117             hp = ast_gethostbyname(v->value, &he);
04118             if (hp) {
04119                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04120                peer->dynamic = 0;
04121             } else {
04122                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04123                peer->dead = 1;
04124             }
04125          }
04126       } else if (!strcasecmp(v->name, "ustothem")) {
04127          if (!dundi_str_to_eid(&testeid, v->value))
04128             peer->us_eid = testeid;
04129          else
04130             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04131       } else if (!strcasecmp(v->name, "include")) {
04132          append_permission(&peer->include, v->value, 1);
04133       } else if (!strcasecmp(v->name, "permit")) {
04134          append_permission(&peer->permit, v->value, 1);
04135       } else if (!strcasecmp(v->name, "noinclude")) {
04136          append_permission(&peer->include, v->value, 0);
04137       } else if (!strcasecmp(v->name, "deny")) {
04138          append_permission(&peer->permit, v->value, 0);
04139       } else if (!strcasecmp(v->name, "register")) {
04140          needregister = ast_true(v->value);
04141       } else if (!strcasecmp(v->name, "order")) {
04142          if (!strcasecmp(v->value, "primary"))
04143             peer->order = 0;
04144          else if (!strcasecmp(v->value, "secondary"))
04145             peer->order = 1;
04146          else if (!strcasecmp(v->value, "tertiary"))
04147             peer->order = 2;
04148          else if (!strcasecmp(v->value, "quartiary"))
04149             peer->order = 3;
04150          else {
04151             ast_log(LOG_WARNING, "'%s' is not a valid order, should be primary, secondary, tertiary or quartiary at line %d\n", v->value, v->lineno);
04152          }
04153       } else if (!strcasecmp(v->name, "qualify")) {
04154          if (!strcasecmp(v->value, "no")) {
04155             peer->maxms = 0;
04156          } else if (!strcasecmp(v->value, "yes")) {
04157             peer->maxms = DEFAULT_MAXMS;
04158          } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
04159             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04160                dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04161             peer->maxms = 0;
04162          }
04163       } else if (!strcasecmp(v->name, "model")) {
04164          if (!strcasecmp(v->value, "inbound"))
04165             peer->model = DUNDI_MODEL_INBOUND;
04166          else if (!strcasecmp(v->value, "outbound")) 
04167             peer->model = DUNDI_MODEL_OUTBOUND;
04168          else if (!strcasecmp(v->value, "symmetric"))
04169             peer->model = DUNDI_MODEL_SYMMETRIC;
04170          else if (!strcasecmp(v->value, "none"))
04171             peer->model = 0;
04172          else {
04173             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04174                v->value, v->lineno);
04175          }
04176       } else if (!strcasecmp(v->name, "precache")) {
04177          if (!strcasecmp(v->value, "inbound"))
04178             peer->pcmodel = DUNDI_MODEL_INBOUND;
04179          else if (!strcasecmp(v->value, "outbound")) 
04180             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04181          else if (!strcasecmp(v->value, "symmetric"))
04182             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04183          else if (!strcasecmp(v->value, "none"))
04184             peer->pcmodel = 0;
04185          else {
04186             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04187                v->value, v->lineno);
04188          }
04189       }
04190    }
04191    (*globalpcmode) |= peer->pcmodel;
04192    if (!peer->model && !peer->pcmodel) {
04193       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04194          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04195       peer->dead = 1;
04196    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04197       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04198          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04199       peer->dead = 1;
04200    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04201       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04202          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04203       peer->dead = 1;
04204    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04205       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04206          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04207    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04208       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", 
04209          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04210    } else { 
04211       if (needregister) {
04212          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04213       }
04214       qualify_peer(peer, 1);
04215    }
04216    AST_LIST_UNLOCK(&peers);
04217 }

static void build_secret char *  secret,
int  seclen
[static]
 

Definition at line 2007 of file pbx_dundi.c.

References ast_base64encode(), build_iv(), and s.

Referenced by check_password(), and load_password().

02008 {
02009    unsigned char tmp[16];
02010    char *s;
02011    build_iv(tmp);
02012    secret[0] = '\0';
02013    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02014    /* Eliminate potential bad characters */
02015    while((s = strchr(secret, ';'))) *s = '+';
02016    while((s = strchr(secret, '/'))) *s = '+';
02017    while((s = strchr(secret, ':'))) *s = '+';
02018    while((s = strchr(secret, '@'))) *s = '+';
02019 }

static void build_transactions struct dundi_request dr,
int  ttl,
int  order,
int *  foundcache,
int *  skipped,
int  blockempty,
int  nocache,
int  modeselect,
dundi_eid skip,
dundi_eid avoid[],
int  directs[]
[static]
 

Definition at line 3323 of file pbx_dundi.c.

References append_transaction(), ast_clear_flag_nonstd, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), cache_lookup(), dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, has_permission(), and option_debug.

Referenced by dundi_lookup_internal(), dundi_precache_internal(), and dundi_query_eid_internal().

03324 {
03325    struct dundi_peer *p;
03326    int x;
03327    int res;
03328    int pass;
03329    int allowconnect;
03330    char eid_str[20];
03331    AST_LIST_LOCK(&peers);
03332    AST_LIST_TRAVERSE(&peers, p, list) {
03333       if (modeselect == 1) {
03334          /* Send the precache to push upstreams only! */
03335          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03336          allowconnect = 1;
03337       } else {
03338          /* Normal lookup / EID query */
03339          pass = has_permission(&p->include, dr->dcontext);
03340          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03341       }
03342       if (skip) {
03343          if (!dundi_eid_cmp(skip, &p->eid))
03344             pass = 0;
03345       }
03346       if (pass) {
03347          if (p->order <= order) {
03348             /* Check order first, then check cache, regardless of
03349                omissions, this gets us more likely to not have an
03350                affected answer. */
03351             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03352                res = 0;
03353                /* Make sure we haven't already seen it and that it won't
03354                   affect our answer */
03355                for (x=0;avoid[x];x++) {
03356                   if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
03357                      /* If not a direct connection, it affects our answer */
03358                      if (directs && !directs[x]) 
03359                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03360                      break;
03361                   }
03362                }
03363                /* Make sure we can ask */
03364                if (allowconnect) {
03365                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03366                      /* Check for a matching or 0 cache entry */
03367                      append_transaction(dr, p, ttl, avoid);
03368                   } else {
03369                      if (option_debug)
03370                         ast_log(LOG_DEBUG, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03371                   }
03372                }
03373             }
03374             *foundcache |= res;
03375          } else if (!*skipped || (p->order < *skipped))
03376             *skipped = p->order;
03377       }
03378    }
03379    AST_LIST_UNLOCK(&peers);
03380 }

static int cache_lookup struct dundi_request req,
dundi_eid peer_eid,
unsigned long  crc32,
int *  lowexpiration
[static]
 

Definition at line 1195 of file pbx_dundi.c.

References cache_lookup_internal(), dundi_request::dcontext, dundi_eid_to_str(), dundi_eid_to_str_short(), dundi_hint_metadata::exten, dundi_request::hmd, key(), dundi_request::number, dundi_request::respcount, and dundi_request::root_eid.

Referenced by build_transactions().

01196 {
01197    char key[256];
01198    char eid_str[20];
01199    char eidroot_str[20];
01200    time_t now;
01201    int res=0;
01202    int res2=0;
01203    char eid_str_full[20];
01204    char tmp[256]="";
01205    int x;
01206 
01207    time(&now);
01208    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01209    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01210    dundi_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01211    snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, crc32);
01212    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01213    snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, 0L);
01214    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01215    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01216    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01217    x = 0;
01218    if (!req->respcount) {
01219       while(!res2) {
01220          /* Look and see if we have a hint that would preclude us from looking at this
01221             peer for this number. */
01222          if (!(tmp[x] = req->number[x])) 
01223             break;
01224          x++;
01225          /* Check for hints */
01226          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, crc32);
01227          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01228          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, 0L);
01229          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01230          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01231          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01232          if (res2) {
01233             if (strlen(tmp) > strlen(req->hmd->exten)) {
01234                /* Update meta data if appropriate */
01235                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01236             }
01237          }
01238       }
01239       res |= res2;
01240    }
01241 
01242    return res;
01243 }

static int cache_lookup_internal time_t  now,
struct dundi_request req,
char *  key,
char *  eid_str_full,
int *  lowexpiration
[static]
 

Definition at line 1121 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_flags, ast_db_del(), ast_db_get(), AST_FLAGS_ALL, ast_get_time_t(), ast_log(), dundi_result::dest, dundi_request::dr, dundi_eid_to_str(), dundi_flags2str(), DUNDI_HINT_DONT_ASK, dundi_str_short_to_eid(), dundi_request::hmd, LOG_DEBUG, option_debug, dundi_request::respcount, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by cache_lookup().

01122 {
01123    char data[1024];
01124    char *ptr, *term, *src;
01125    int tech;
01126    struct ast_flags flags;
01127    int weight;
01128    int length;
01129    int z;
01130    char fs[256];
01131 
01132    /* Build request string */
01133    if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
01134       time_t timeout;
01135       ptr = data;
01136       if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
01137          int expiration = timeout - now;
01138          if (expiration > 0) {
01139             if (option_debug)
01140                ast_log(LOG_DEBUG, "Found cache expiring in %d seconds!\n", expiration);
01141             ptr += length + 1;
01142             while((sscanf(ptr, "%d/%d/%d/%n", &(flags.flags), &weight, &tech, &length) == 3)) {
01143                ptr += length;
01144                term = strchr(ptr, '|');
01145                if (term) {
01146                   *term = '\0';
01147                   src = strrchr(ptr, '/');
01148                   if (src) {
01149                      *src = '\0';
01150                      src++;
01151                   } else
01152                      src = "";
01153                   if (option_debug)
01154                      ast_log(LOG_DEBUG, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", 
01155                         tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
01156                   /* Make sure it's not already there */
01157                   for (z=0;z<req->respcount;z++) {
01158                      if ((req->dr[z].techint == tech) &&
01159                          !strcmp(req->dr[z].dest, ptr)) 
01160                            break;
01161                   }
01162                   if (z == req->respcount) {
01163                      /* Copy into parent responses */
01164                      ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);   
01165                      req->dr[req->respcount].weight = weight;
01166                      req->dr[req->respcount].techint = tech;
01167                      req->dr[req->respcount].expiration = expiration;
01168                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
01169                      dundi_eid_to_str(req->dr[req->respcount].eid_str, 
01170                         sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
01171                      ast_copy_string(req->dr[req->respcount].dest, ptr,
01172                         sizeof(req->dr[req->respcount].dest));
01173                      ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
01174                         sizeof(req->dr[req->respcount].tech));
01175                      req->respcount++;
01176                      ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK); 
01177                   } else if (req->dr[z].weight > weight)
01178                      req->dr[z].weight = weight;
01179                   ptr = term + 1;
01180                }
01181             }
01182             /* We found *something* cached */
01183             if (expiration < *lowexpiration)
01184                *lowexpiration = expiration;
01185             return 1;
01186          } else 
01187             ast_db_del("dundi/cache", key);
01188       } else 
01189          ast_db_del("dundi/cache", key);
01190    }
01191       
01192    return 0;
01193 }

static int cache_save dundi_eid eidpeer,
struct dundi_request req,
int  start,
int  unaffected,
int  expiration,
int  push
[static]
 

Definition at line 842 of file pbx_dundi.c.

References dundi_request::crc32, dundi_request::dcontext, dundi_result::dest, dundi_request::dr, dundi_eid_to_str_short(), dundi_result::eid, dundi_result::flags, dundi_request::number, dundi_request::respcount, dundi_request::root_eid, dundi_result::techint, and dundi_result::weight.

00843 {
00844    int x;
00845    char key1[256];
00846    char key2[256];
00847    char data[1024];
00848    char eidpeer_str[20];
00849    char eidroot_str[20];
00850    time_t timeout;
00851 
00852    if (expiration < 1)  
00853       expiration = dundi_cache_time;
00854 
00855    /* Keep pushes a little longer, cut pulls a little short */
00856    if (push)
00857       expiration += 10;
00858    else
00859       expiration -= 10;
00860    if (expiration < 1)
00861       expiration = 1;
00862    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00863    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00864    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08lx", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00865    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00866    /* Build request string */
00867    time(&timeout);
00868    timeout += expiration;
00869    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00870    for (x=start;x<req->respcount;x++) {
00871       /* Skip anything with an illegal pipe in it */
00872       if (strchr(req->dr[x].dest, '|'))
00873          continue;
00874       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", 
00875          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 
00876          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00877    }
00878    ast_db_put("dundi/cache", key1, data);
00879    ast_db_put("dundi/cache", key2, data);
00880    return 0;
00881 }

static int cache_save_hint dundi_eid eidpeer,
struct dundi_request req,
struct dundi_hint hint,
int  expiration
[static]
 

Definition at line 805 of file pbx_dundi.c.

References ast_db_put(), ast_log(), ast_test_flag_nonstd, dundi_request::crc32, dundi_hint::data, dundi_request::dcontext, dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, LOG_DEBUG, option_debug, and dundi_request::root_eid.

00806 {
00807    int unaffected;
00808    char key1[256];
00809    char key2[256];
00810    char eidpeer_str[20];
00811    char eidroot_str[20];
00812    char data[80];
00813    time_t timeout;
00814 
00815    if (expiration < 0)
00816       expiration = dundi_cache_time;
00817 
00818    /* Only cache hint if "don't ask" is there... */
00819    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))   
00820       return 0;
00821 
00822    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00823 
00824    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00825    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00826    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08lx", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00827    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00828 
00829    time(&timeout);
00830    timeout += expiration;
00831    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00832    
00833    ast_db_put("dundi/cache", key1, data);
00834    if (option_debug)
00835       ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key1);
00836    ast_db_put("dundi/cache", key2, data);
00837    if (option_debug)
00838       ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key2);
00839    return 0;
00840 }

static void cancel_request struct dundi_request dr  )  [static]
 

Definition at line 3297 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, dr, DUNDI_COMMAND_CANCEL, and dundi_send().

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03298 {
03299    struct dundi_transaction *trans;
03300 
03301    AST_LIST_LOCK(&peers);
03302    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03303       /* Orphan transaction from request */
03304       trans->parent = NULL;
03305       /* Send final cancel */
03306       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03307    }
03308    AST_LIST_UNLOCK(&peers);
03309 }

static int check_key struct dundi_peer peer,
unsigned char *  newkey,
unsigned char *  newsig,
unsigned long  keycrc32
[static]
 

Definition at line 1449 of file pbx_dundi.c.

References aes_decrypt_key128(), aes_encrypt_key128(), ast_check_signature_bin, ast_decrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_eid_to_str(), dundi_peer::eid, key(), LOG_DEBUG, LOG_NOTICE, and option_debug.

01450 {
01451    unsigned char dst[128];
01452    int res;
01453    struct ast_key *key, *skey;
01454    char eid_str[20];
01455    if (option_debug)
01456       ast_log(LOG_DEBUG, "Expected '%08lx' got '%08lx'\n", peer->them_keycrc32, keycrc32);
01457    if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
01458       /* A match */
01459       return 1;
01460    } else if (!newkey || !newsig)
01461       return 0;
01462    if (!memcmp(peer->rxenckey, newkey, 128) &&
01463        !memcmp(peer->rxenckey + 128, newsig, 128)) {
01464       /* By definition, a match */
01465       return 1;
01466    }
01467    /* Decrypt key */
01468    key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01469    if (!key) {
01470       ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
01471          peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01472       return -1;
01473    }
01474 
01475    skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01476    if (!skey) {
01477       ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
01478          peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01479       return -1;
01480    }
01481 
01482    /* First check signature */
01483    res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
01484    if (res) 
01485       return 0;
01486 
01487    res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
01488    if (res != 16) {
01489       if (res >= 0)
01490          ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
01491       return 0;
01492    }
01493    /* Decrypted, passes signature */
01494    if (option_debug)
01495       ast_log(LOG_DEBUG, "Wow, new key combo passed signature and decrypt!\n");
01496    memcpy(peer->rxenckey, newkey, 128);
01497    memcpy(peer->rxenckey + 128, newsig, 128);
01498    peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
01499    aes_decrypt_key128(dst, &peer->them_dcx);
01500    aes_encrypt_key128(dst, &peer->them_ecx);
01501    return 1;
01502 }

static void check_password void   )  [static]
 

Definition at line 2074 of file pbx_dundi.c.

References build_secret(), and save_secret().

Referenced by network_thread().

02075 {
02076    char oldsecret[80];
02077    time_t now;
02078    
02079    time(&now); 
02080 #if 0
02081    printf("%ld/%ld\n", now, rotatetime);
02082 #endif
02083    if ((now - rotatetime) >= 0) {
02084       /* Time to rotate keys */
02085       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02086       build_secret(cursecret, sizeof(cursecret));
02087       save_secret(cursecret, oldsecret);
02088    }
02089 }

static int check_request struct dundi_request dr  )  [static]
 

Definition at line 3422 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and dr.

Referenced by dundi_lookup_internal().

03423 {
03424    struct dundi_request *cur;
03425 
03426    AST_LIST_LOCK(&peers);
03427    AST_LIST_TRAVERSE(&requests, cur, list) {
03428       if (cur == dr)
03429          break;
03430    }
03431    AST_LIST_UNLOCK(&peers);
03432    
03433    return cur ? 1 : 0;
03434 }

static char* complete_peer_4 const char *  line,
const char *  word,
int  pos,
int  state
[static]
 

Definition at line 2258 of file pbx_dundi.c.

References complete_peer_helper().

02259 {
02260    return complete_peer_helper(line, word, pos, state, 3);
02261 }

static char* complete_peer_helper const char *  line,
const char *  word,
int  pos,
int  state,
int  rpos
[static]
 

Definition at line 2238 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, dundi_eid_to_str(), dundi_peer::eid, len, and s.

Referenced by complete_peer_4().

02239 {
02240    int which=0, len;
02241    char *ret = NULL;
02242    struct dundi_peer *p;
02243    char eid_str[20];
02244 
02245    if (pos != rpos)
02246       return NULL;
02247    AST_LIST_LOCK(&peers);
02248    len = strlen(word);
02249    AST_LIST_TRAVERSE(&peers, p, list) {
02250       const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02251       if (!strncasecmp(word, s, len) && ++which > state)
02252          ret = ast_strdup(s);
02253    }
02254    AST_LIST_UNLOCK(&peers);
02255    return ret;
02256 }

static struct dundi_transaction * create_transaction struct dundi_peer p  )  [static]
 

Definition at line 2766 of file pbx_dundi.c.

References dundi_peer::addr, apply_peer(), ast_calloc, AST_LIST_INSERT_HEAD, ast_set_flag, DUNDI_DEFAULT_RETRANS_TIMER, FLAG_SENDFULLKEY, FLAG_STOREHIST, and get_trans_id().

Referenced by append_transaction(), do_register(), find_transaction(), and qualify_peer().

02767 {
02768    struct dundi_transaction *trans;
02769    int tid;
02770    
02771    /* Don't allow creation of transactions to non-registered peers */
02772    if (p && !p->addr.sin_addr.s_addr)
02773       return NULL;
02774    tid = get_trans_id();
02775    if (tid < 1)
02776       return NULL;
02777    if (!(trans = ast_calloc(1, sizeof(*trans))))
02778       return NULL;
02779 
02780    if (global_storehistory) {
02781       trans->start = ast_tvnow();
02782       ast_set_flag(trans, FLAG_STOREHIST);
02783    }
02784    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02785    trans->autokillid = -1;
02786    if (p) {
02787       apply_peer(trans, p);
02788       if (!p->sentfullkey)
02789          ast_set_flag(trans, FLAG_SENDFULLKEY);
02790    }
02791    trans->strans = tid;
02792    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02793    
02794    return trans;
02795 }

static int decrypt_memcpy unsigned char *  dst,
unsigned char *  src,
int  len,
unsigned char *  iv,
aes_decrypt_ctx dcx
[static]
 

Definition at line 1339 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

01340 {
01341    unsigned char lastblock[16];
01342    int x;
01343    memcpy(lastblock, iv, sizeof(lastblock));
01344    while(len > 0) {
01345       aes_decrypt(src, dst, dcx);
01346       for (x=0;x<16;x++)
01347          dst[x] ^= lastblock[x];
01348       memcpy(lastblock, src, sizeof(lastblock));
01349       dst += 16;
01350       src += 16;
01351       len -= 16;
01352    }
01353    return 0;
01354 }

static void destroy_map struct dundi_mapping map  )  [static]
 

Definition at line 3866 of file pbx_dundi.c.

References free, and map.

Referenced by prune_mappings().

03867 {
03868    free(map);
03869 }

static void destroy_packet struct dundi_packet pack,
int  needfree
[static]
 

Definition at line 2813 of file pbx_dundi.c.

References AST_LIST_REMOVE, ast_sched_del(), free, and sched.

Referenced by ack_trans().

02814 {
02815    if (pack->parent)
02816       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02817    if (pack->retransid > -1)
02818       ast_sched_del(sched, pack->retransid);
02819    if (needfree)
02820       free(pack);
02821    else
02822       pack->retransid = -1;
02823 }

static void destroy_packets struct packetlist *  p  )  [static]
 

Definition at line 1902 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, ast_sched_del(), free, and sched.

Referenced by ack_trans(), and handle_frame().

01903 {
01904    struct dundi_packet *pack;
01905    
01906    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01907       if (pack->retransid > -1)
01908          ast_sched_del(sched, pack->retransid);
01909       free(pack);
01910    }
01911 }

static void destroy_peer struct dundi_peer peer  )  [static]
 

Definition at line 3853 of file pbx_dundi.c.

References ast_sched_del(), destroy_permissions(), destroy_trans(), free, and sched.

03854 {
03855    if (peer->registerid > -1)
03856       ast_sched_del(sched, peer->registerid);
03857    if (peer->regtrans)
03858       destroy_trans(peer->regtrans, 0);
03859    if (peer->qualifyid > -1)
03860       ast_sched_del(sched, peer->qualifyid);
03861    destroy_permissions(&peer->permit);
03862    destroy_permissions(&peer->include);
03863    free(peer);
03864 }

static void destroy_permissions struct permissionlist *  permlist  )  [static]
 

Definition at line 3845 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by build_peer(), and destroy_peer().

03846 {
03847    struct permission *perm;
03848 
03849    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03850       free(perm);
03851 }

static void destroy_trans struct dundi_transaction trans,
int  fromtimeout
[static]
 

Definition at line 2825 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_strlen_zero(), ast_test_flag, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, free, LOG_NOTICE, dundi_transaction::start, and dundi_transaction::them_eid.

Referenced by abort_request(), destroy_peer(), do_autokill(), do_register(), dundi_precache_thread(), dundi_query_thread(), dundi_rexmit(), handle_frame(), precache_transactions(), and qualify_peer().

02826 {
02827    struct dundi_peer *peer;
02828    int ms;
02829    int x;
02830    int cnt;
02831    char eid_str[20];
02832    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02833       AST_LIST_TRAVERSE(&peers, peer, list) {
02834          if (peer->regtrans == trans)
02835             peer->regtrans = NULL;
02836          if (peer->qualtrans == trans) {
02837             if (fromtimeout) {
02838                if (peer->lastms > -1)
02839                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02840                peer->lastms = -1;
02841             } else {
02842                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02843                if (ms < 1)
02844                   ms = 1;
02845                if (ms < peer->maxms) {
02846                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02847                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02848                } else if (peer->lastms < peer->maxms) {
02849                   ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
02850                }
02851                peer->lastms = ms;
02852             }
02853             peer->qualtrans = NULL;
02854          }
02855          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02856             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02857                if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
02858                   peer->avgms = 0;
02859                   cnt = 0;
02860                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02861                      free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02862                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02863                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02864                      peer->lookups[x] = peer->lookups[x-1];
02865                      if (peer->lookups[x]) {
02866                         peer->avgms += peer->lookuptimes[x];
02867                         cnt++;
02868                      }
02869                   }
02870                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
02871                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
02872                   if (peer->lookups[0]) {
02873                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
02874                      peer->avgms += peer->lookuptimes[0];
02875                      cnt++;
02876                   }
02877                   if (cnt)
02878                      peer->avgms /= cnt;
02879                }
02880             }
02881          }
02882       }
02883    }
02884    if (trans->parent) {
02885       /* Unlink from parent if appropriate */
02886       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
02887       if (AST_LIST_EMPTY(&trans->parent->trans)) {
02888          /* Wake up sleeper */
02889          if (trans->parent->pfds[1] > -1) {
02890             write(trans->parent->pfds[1], "killa!", 6);
02891          }
02892       }
02893    }
02894    /* Unlink from all trans */
02895    AST_LIST_REMOVE(&alltrans, trans, all);
02896    destroy_packets(&trans->packets);
02897    destroy_packets(&trans->lasttrans);
02898    if (trans->autokillid > -1)
02899       ast_sched_del(sched, trans->autokillid);
02900    trans->autokillid = -1;
02901    if (trans->thread) {
02902       /* If used by a thread, mark as dead and be done */
02903       ast_set_flag(trans, FLAG_DEAD);
02904    } else
02905       free(trans);
02906 }

static int discover_transactions struct dundi_request dr  )  [static]
 

Definition at line 3148 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, and dundi_discover().

Referenced by dundi_lookup_internal().

03149 {
03150    struct dundi_transaction *trans;
03151    AST_LIST_LOCK(&peers);
03152    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03153       dundi_discover(trans);
03154    }
03155    AST_LIST_UNLOCK(&peers);
03156    return 0;
03157 }

static int do_autokill void *  data  )  [static]
 

Definition at line 3003 of file pbx_dundi.c.

References ast_log(), dundi_transaction::autokillid, destroy_trans(), dundi_eid_to_str(), LOG_NOTICE, and dundi_transaction::them_eid.

Referenced by dundi_discover(), and dundi_query().

03004 {
03005    struct dundi_transaction *trans = data;
03006    char eid_str[20];
03007    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03008       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03009    trans->autokillid = -1;
03010    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03011    return 0;
03012 }

static int do_qualify void *  data  )  [static]
 

Definition at line 4013 of file pbx_dundi.c.

References qualify_peer().

Referenced by qualify_peer().

04014 {
04015    struct dundi_peer *peer;
04016    peer = data;
04017    peer->qualifyid = -1;
04018    qualify_peer(peer, 0);
04019    return 0;
04020 }

static int do_register void *  data  )  [static]
 

Definition at line 3986 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), destroy_trans(), DUNDI_COMMAND_REGREQ, DUNDI_DEFAULT_VERSION, dundi_eid_to_str(), dundi_ie_append_eid(), dundi_ie_append_short(), DUNDI_IE_EID, DUNDI_IE_EXPIRATION, DUNDI_IE_VERSION, dundi_send(), dundi_peer::eid, FLAG_ISREG, LOG_NOTICE, option_debug, and sched.

03987 {
03988    struct dundi_ie_data ied;
03989    struct dundi_peer *peer = data;
03990    char eid_str[20];
03991    char eid_str2[20];
03992    if (option_debug)
03993       ast_log(LOG_DEBUG, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
03994    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
03995    /* Destroy old transaction if there is one */
03996    if (peer->regtrans)
03997       destroy_trans(peer->regtrans, 0);
03998    peer->regtrans = create_transaction(peer);
03999    if (peer->regtrans) {
04000       ast_set_flag(peer->regtrans, FLAG_ISREG);
04001       memset(&ied, 0, sizeof(ied));
04002       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04003       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04004       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04005       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04006       
04007    } else
04008       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04009 
04010    return 0;
04011 }

static int do_register_expire void *  data  )  [static]
 

Note:
Called with the peers list already locked

Definition at line 1272 of file pbx_dundi.c.

References dundi_peer::addr, ast_log(), dundi_eid_to_str(), dundi_peer::eid, LOG_DEBUG, and option_debug.

Referenced by handle_command_response(), and populate_addr().

01273 {
01274    struct dundi_peer *peer = data;
01275    char eid_str[20];
01276    if (option_debug)
01277       ast_log(LOG_DEBUG, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01278    peer->registerexpire = -1;
01279    peer->lastms = 0;
01280    memset(&peer->addr, 0, sizeof(peer->addr));
01281    return 0;
01282 }

static int dundi_ack struct dundi_transaction trans,
int  final
[static]
 

Definition at line 360 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00361 {
00362    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00363 }

static int dundi_answer_entity struct dundi_transaction trans,
struct dundi_ies ies,
char *  ccontext
[static]
 

Definition at line 746 of file pbx_dundi.c.

References ast_calloc, ast_log(), ast_pthread_create, dundi_query_state::called_context, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_query_thread(), dundi_send(), dundi_query_state::eids, dundi_query_state::fluffy, free, ies, LOG_DEBUG, LOG_WARNING, option_debug, dundi_query_state::reqeid, s, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

Referenced by handle_command_response().

00747 {
00748    struct dundi_query_state *st;
00749    int totallen;
00750    int x;
00751    int skipfirst=0;
00752    struct dundi_ie_data ied;
00753    char eid_str[20];
00754    char *s;
00755    pthread_t lookupthread;
00756    pthread_attr_t attr;
00757    if (ies->eidcount > 1) {
00758       /* Since it is a requirement that the first EID is the authenticating host
00759          and the last EID is the root, it is permissible that the first and last EID
00760          could be the same.  In that case, we should go ahead copy only the "root" section
00761          since we will not need it for authentication. */
00762       if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00763          skipfirst = 1;
00764    }
00765    totallen = sizeof(struct dundi_query_state);
00766    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00767    st = ast_calloc(1, totallen);
00768    if (st) {
00769       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00770       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00771       st->trans = trans;
00772       st->ttl = ies->ttl - 1;
00773       if (st->ttl < 0)
00774          st->ttl = 0;
00775       s = st->fluffy;
00776       for (x=skipfirst;ies->eids[x];x++) {
00777          st->eids[x-skipfirst] = (dundi_eid *)s;
00778          *st->eids[x-skipfirst] = *ies->eids[x];
00779          s += sizeof(dundi_eid);
00780       }
00781       if (option_debug)
00782          ast_log(LOG_DEBUG, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00783       pthread_attr_init(&attr);
00784       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00785       trans->thread = 1;
00786       if (ast_pthread_create(&lookupthread, &attr, dundi_query_thread, st)) {
00787          trans->thread = 0;
00788          ast_log(LOG_WARNING, "Unable to create thread!\n");
00789          free(st);
00790          memset(&ied, 0, sizeof(ied));
00791          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00792          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00793          return -1;
00794       }
00795    } else {
00796       ast_log(LOG_WARNING, "Out of memory!\n");
00797       memset(&ied, 0, sizeof(ied));
00798       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00799       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00800       return -1;
00801    }
00802    return 0;
00803 }

static int dundi_answer_query struct dundi_transaction trans,
struct dundi_ies ies,
char *  ccontext
[static]
 

Definition at line 1034 of file pbx_dundi.c.

References ast_calloc, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create, dundi_query_state::called_context, dundi_query_state::called_number, dundi_mapping::dcontext, dundi_query_state::directs, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_DPRESPONSE, dundi_eid_cmp(), dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_lookup_thread(), dundi_send(), dundi_query_state::eids, dundi_query_state::fluffy, free, ies, LOG_DEBUG, LOG_WARNING, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, option_debug, s, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

Referenced by handle_command_response().

01035 {
01036    struct dundi_query_state *st;
01037    int totallen;
01038    int x;
01039    struct dundi_ie_data ied;
01040    char *s;
01041    struct dundi_mapping *cur;
01042    int mapcount = 0;
01043    int skipfirst = 0;
01044    
01045    pthread_t lookupthread;
01046    pthread_attr_t attr;
01047    totallen = sizeof(struct dundi_query_state);
01048    /* Count matching map entries */
01049    AST_LIST_TRAVERSE(&mappings, cur, list) {
01050       if (!strcasecmp(cur->dcontext, ccontext))
01051          mapcount++;
01052    }
01053    /* If no maps, return -1 immediately */
01054    if (!mapcount)
01055       return -1;
01056 
01057    if (ies->eidcount > 1) {
01058       /* Since it is a requirement that the first EID is the authenticating host
01059          and the last EID is the root, it is permissible that the first and last EID
01060          could be the same.  In that case, we should go ahead copy only the "root" section
01061          since we will not need it for authentication. */
01062       if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01063          skipfirst = 1;
01064    }
01065 
01066    totallen += mapcount * sizeof(struct dundi_mapping);
01067    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01068    st = ast_calloc(1, totallen);
01069    if (st) {
01070       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
01071       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01072       st->trans = trans;
01073       st->ttl = ies->ttl - 1;
01074       st->nocache = ies->cbypass;
01075       if (st->ttl < 0)
01076          st->ttl = 0;
01077       s = st->fluffy;
01078       for (x=skipfirst;ies->eids[x];x++) {
01079          st->eids[x-skipfirst] = (dundi_eid *)s;
01080          *st->eids[x-skipfirst] = *ies->eids[x];
01081          st->directs[x-skipfirst] = ies->eid_direct[x];
01082          s += sizeof(dundi_eid);
01083       }
01084       /* Append mappings */
01085       x = 0;
01086       st->maps = (struct dundi_mapping *)s;
01087       AST_LIST_TRAVERSE(&mappings, cur, list) {
01088          if (!strcasecmp(cur->dcontext, ccontext)) {
01089             if (x < mapcount) {
01090                st->maps[x] = *cur;
01091                st->maps[x].list.next = NULL;
01092                x++;
01093             }
01094          }
01095       }
01096       st->nummaps = mapcount;
01097       if (option_debug)
01098          ast_log(LOG_DEBUG, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
01099       pthread_attr_init(&attr);
01100       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01101       trans->thread = 1;
01102       if (ast_pthread_create(&lookupthread, &attr, dundi_lookup_thread, st)) {
01103          trans->thread = 0;
01104          ast_log(LOG_WARNING, "Unable to create thread!\n");
01105          free(st);
01106          memset(&ied, 0, sizeof(ied));
01107          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01108          dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01109          return -1;
01110       }
01111    } else {
01112       ast_log(LOG_WARNING, "Out of memory!\n");
01113       memset(&ied, 0, sizeof(ied));
01114       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01115       dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01116       return -1;
01117    }
01118    return 0;
01119 }

static int dundi_canmatch struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data
[static]
 

Definition at line 4263 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04264 {
04265    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04266 }

static void dundi_debug_output const char *  data  )  [static]
 

Definition at line 267 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

00268 {
00269    if (dundidebug)
00270       ast_verbose("%s", data);
00271 }

static struct dundi_hdr* dundi_decrypt struct dundi_transaction trans,
unsigned char *  dst,
int *  dstlen,
struct dundi_hdr ohdr,
struct dundi_encblock src,
int  srclen
[static]
 

Definition at line 1356 of file pbx_dundi.c.

References ast_log(), dundi_transaction::dcx, decrypt_memcpy(), dundi_encblock::encdata, dundi_encblock::iv, LOG_DEBUG, option_debug, and space.

01357 {
01358    int space = *dstlen;
01359    unsigned long bytes;
01360    struct dundi_hdr *h;
01361    unsigned char *decrypt_space;
01362    decrypt_space = alloca(srclen);
01363    if (!decrypt_space)
01364       return NULL;
01365    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01366    /* Setup header */
01367    h = (struct dundi_hdr *)dst;
01368    *h = *ohdr;
01369    bytes = space - 6;
01370    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01371       if (option_debug)
01372          ast_log(LOG_DEBUG, "Ouch, uncompress failed :(\n");
01373       return NULL;
01374    }
01375    /* Update length */
01376    *dstlen = bytes + 6;
01377    /* Return new header */
01378    return h;
01379 }

static int dundi_discover struct dundi_transaction trans  )  [static]
 

Definition at line 3036 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, do_autokill(), DUNDI_COMMAND_DPDISCOVER, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append(), dundi_ie_append_eid(), dundi_ie_append_eid_appropriately(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CACHEBYPASS, DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID_DIRECT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, sched, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by discover_transactions().

03037 {
03038    struct dundi_ie_data ied;
03039    int x;
03040    if (!trans->parent) {
03041       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03042       return -1;
03043    }
03044    memset(&ied, 0, sizeof(ied));
03045    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03046    if (!dundi_eid_zero(&trans->us_eid))
03047       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03048    for (x=0;x<trans->eidcount;x++)
03049       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03050    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03051    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03052    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03053    if (trans->parent->cbypass)
03054       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03055    if (trans->autokilltimeout)
03056       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03057    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03058 }

static int dundi_do_debug int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2155 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02156 {
02157    if (argc != 2)
02158       return RESULT_SHOWUSAGE;
02159    dundidebug = 1;
02160    ast_cli(fd, "DUNDi Debugging Enabled\n");
02161    return RESULT_SUCCESS;
02162 }

static int dundi_do_lookup int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2280 of file pbx_dundi.c.

References ast_cli(), context, dr, dundi_flags2str(), dundi_lookup(), MAX_RESULTS, RESULT_SHOWUSAGE, and sort_results().

02281 {
02282    int res;
02283    char tmp[256];
02284    char fs[80] = "";
02285    char *context;
02286    int x;
02287    int bypass = 0;
02288    struct dundi_result dr[MAX_RESULTS];
02289    struct timeval start;
02290    if ((argc < 3) || (argc > 4))
02291       return RESULT_SHOWUSAGE;
02292    if (argc > 3) {
02293       if (!strcasecmp(argv[3], "bypass"))
02294          bypass=1;
02295       else
02296          return RESULT_SHOWUSAGE;
02297    }
02298    ast_copy_string(tmp, argv[2], sizeof(tmp));
02299    context = strchr(tmp, '@');
02300    if (context) {
02301       *context = '\0';
02302       context++;
02303    }
02304    start = ast_tvnow();
02305    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02306    
02307    if (res < 0) 
02308       ast_cli(fd, "DUNDi lookup returned error.\n");
02309    else if (!res) 
02310       ast_cli(fd, "DUNDi lookup returned no results.\n");
02311    else
02312       sort_results(dr, res);
02313    for (x=0;x<res;x++) {
02314       ast_cli(fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags));
02315       ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02316    }
02317    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02318    return RESULT_SUCCESS;
02319 }

static int dundi_do_precache int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2321 of file pbx_dundi.c.

References ast_cli(), context, dundi_precache(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02322 {
02323    int res;
02324    char tmp[256];
02325    char *context;
02326    struct timeval start;
02327    if ((argc < 3) || (argc > 3))
02328       return RESULT_SHOWUSAGE;
02329    ast_copy_string(tmp, argv[2], sizeof(tmp));
02330    context = strchr(tmp, '@');
02331    if (context) {
02332       *context = '\0';
02333       context++;
02334    }
02335    start = ast_tvnow();
02336    res = dundi_precache(context, tmp);
02337    
02338    if (res < 0) 
02339       ast_cli(fd, "DUNDi precache returned error.\n");
02340    else if (!res) 
02341       ast_cli(fd, "DUNDi precache returned no error.\n");
02342    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02343    return RESULT_SUCCESS;
02344 }

static int dundi_do_query int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2346 of file pbx_dundi.c.

References ast_cli(), context, dundi_entity_info::country, dundi_query_eid(), dundi_str_to_eid(), dundi_entity_info::email, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_entity_info::stateprov.

02347 {
02348    int res;
02349    char tmp[256];
02350    char *context;
02351    dundi_eid eid;
02352    struct dundi_entity_info dei;
02353    if ((argc < 3) || (argc > 3))
02354       return RESULT_SHOWUSAGE;
02355    if (dundi_str_to_eid(&eid, argv[2])) {
02356       ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
02357       return RESULT_SHOWUSAGE;
02358    }
02359    ast_copy_string(tmp, argv[2], sizeof(tmp));
02360    context = strchr(tmp, '@');
02361    if (context) {
02362       *context = '\0';
02363       context++;
02364    }
02365    res = dundi_query_eid(&dei, context, eid);
02366    if (res < 0) 
02367       ast_cli(fd, "DUNDi Query EID returned error.\n");
02368    else if (!res) 
02369       ast_cli(fd, "DUNDi Query EID returned no results.\n");
02370    else {
02371       ast_cli(fd, "DUNDi Query EID succeeded:\n");
02372       ast_cli(fd, "Department:      %s\n", dei.orgunit);
02373       ast_cli(fd, "Organization:    %s\n", dei.org);
02374       ast_cli(fd, "City/Locality:   %s\n", dei.locality);
02375       ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
02376       ast_cli(fd, "Country:         %s\n", dei.country);
02377       ast_cli(fd, "E-mail:          %s\n", dei.email);
02378       ast_cli(fd, "Phone:           %s\n", dei.phone);
02379       ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
02380    }
02381    return RESULT_SUCCESS;
02382 }

static int dundi_do_store_history int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2164 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02165 {
02166    if (argc != 3)
02167       return RESULT_SHOWUSAGE;
02168    global_storehistory = 1;
02169    ast_cli(fd, "DUNDi History Storage Enabled\n");
02170    return RESULT_SUCCESS;
02171 }

static int dundi_encrypt struct dundi_transaction trans,
struct dundi_packet pack
[static]
 

Definition at line 1381 of file pbx_dundi.c.

References ast_log(), ast_set_flag, ast_test_flag, build_iv(), dundi_transaction::dcx, DUNDI_COMMAND_ENCRYPT, dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_int(), dundi_ie_append_raw(), DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_KEYCRC32, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, dundi_transaction::ecx, encrypt_memcpy(), find_peer(), FLAG_SENDFULLKEY, len, LOG_DEBUG, LOG_NOTICE, option_debug, dundi_transaction::them_eid, update_key(), and dundi_transaction::us_eid.

Referenced by dundi_send().

01382 {
01383    unsigned char *compress_space;
01384    int len;
01385    int res;
01386    unsigned long bytes;
01387    struct dundi_ie_data ied;
01388    struct dundi_peer *peer;
01389    unsigned char iv[16];
01390    len = pack->datalen + pack->datalen / 100 + 42;
01391    compress_space = alloca(len);
01392    if (compress_space) {
01393       memset(compress_space, 0, len);
01394       /* We care about everthing save the first 6 bytes of header */
01395       bytes = len;
01396       res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
01397       if (res != Z_OK) {
01398          if (option_debug)
01399             ast_log(LOG_DEBUG, "Ouch, compression failed!\n");
01400          return -1;
01401       }
01402       memset(&ied, 0, sizeof(ied));
01403       /* Say who we are */
01404       if (!pack->h->iseqno && !pack->h->oseqno) {
01405          /* Need the key in the first copy */
01406          if (!(peer = find_peer(&trans->them_eid))) 
01407             return -1;
01408          if (update_key(peer))
01409             return -1;
01410          if (!peer->sentfullkey)
01411             ast_set_flag(trans, FLAG_SENDFULLKEY); 
01412          /* Append key data */
01413          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
01414          if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
01415             dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
01416             dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
01417          } else {
01418             dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
01419          }
01420          /* Setup contexts */
01421          trans->ecx = peer->us_ecx;
01422          trans->dcx = peer->us_dcx;
01423 
01424          /* We've sent the full key */
01425          peer->sentfullkey = 1;
01426       }
01427       /* Build initialization vector */
01428       build_iv(iv);
01429       /* Add the field, rounded up to 16 bytes */
01430       dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
01431       /* Copy the data */
01432       if ((ied.pos + bytes) >= sizeof(ied.buf)) {
01433          ast_log(LOG_NOTICE, "Final packet too large!\n");
01434          return -1;
01435       }
01436       encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
01437       ied.pos += ((bytes + 15) / 16) * 16;
01438       /* Reconstruct header */
01439       pack->datalen = sizeof(struct dundi_hdr);
01440       pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
01441       pack->h->cmdflags = 0;
01442       memcpy(pack->h->ies, ied.buf, ied.pos);
01443       pack->datalen += ied.pos;
01444       return 0;
01445    }
01446    return -1;
01447 }

static void dundi_error_output const char *  data  )  [static]
 

Definition at line 273 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00274 {
00275    ast_log(LOG_WARNING, "%s", data);
00276 }

static int dundi_exec struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data
[static]
 

Definition at line 4268 of file pbx_dundi.c.

References ast_log(), ast_strlen_zero(), ast_test_flag, DUNDI_FLAG_EXISTS, dundi_lookup(), ast_channel::exten, LOG_NOTICE, ast_channel::macroexten, MAX_RESULTS, pbx_builtin_getvar_helper(), and sort_results().

04269 {
04270    struct dundi_result results[MAX_RESULTS];
04271    int res;
04272    int x=0;
04273    char req[1024];
04274    const char *dundiargs;
04275    struct ast_app *dial;
04276    
04277    if (!strncasecmp(context, "macro-", 6)) {
04278       if (!chan) {   
04279          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04280          return -1;
04281       }
04282       /* If done as a macro, use macro extension */
04283       if (!strcasecmp(exten, "s")) {
04284          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04285          if (ast_strlen_zero(exten))
04286             exten = chan->macroexten;
04287          if (ast_strlen_zero(exten))
04288             exten = chan->exten;
04289          if (ast_strlen_zero(exten)) { 
04290             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04291             return -1;
04292          }
04293       }
04294       if (ast_strlen_zero(data))
04295          data = "e164";
04296    } else {
04297       if (ast_strlen_zero(data))
04298          data = context;
04299    }
04300    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04301    if (res > 0) {
04302       sort_results(results, res);
04303       for (x=0;x<res;x++) {
04304          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04305             if (!--priority)
04306                break;
04307          }
04308       }
04309    }
04310    if (x < res) {
04311       /* Got a hit! */
04312       dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
04313       snprintf(req, sizeof(req), "%s/%s||%s", results[x].tech, results[x].dest, 
04314          S_OR(dundiargs, ""));
04315       dial = pbx_findapp("Dial");
04316       if (dial)
04317          res = pbx_exec(chan, dial, req);
04318    } else
04319       res = -1;
04320    return res;
04321 }

static int dundi_exists struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data
[static]
 

Definition at line 4258 of file pbx_dundi.c.

References DUNDI_FLAG_EXISTS, and dundi_helper().

04259 {
04260    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04261 }

static int dundi_flush int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2173 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, DUNDI_TIMING_HISTORY, free, and RESULT_SHOWUSAGE.

02174 {
02175    int stats = 0;
02176    if ((argc < 2) || (argc > 3))
02177       return RESULT_SHOWUSAGE;
02178    if (argc > 2) {
02179       if (!strcasecmp(argv[2], "stats"))
02180          stats = 1;
02181       else
02182          return RESULT_SHOWUSAGE;
02183    }
02184    if (stats) {
02185       /* Flush statistics */
02186       struct dundi_peer *p;
02187       int x;
02188       AST_LIST_LOCK(&peers);
02189       AST_LIST_TRAVERSE(&peers, p, list) {
02190          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02191             if (p->lookups[x])
02192                free(p->lookups[x]);
02193             p->lookups[x] = NULL;
02194             p->lookuptimes[x] = 0;
02195          }
02196          p->avgms = 0;
02197       }
02198       AST_LIST_UNLOCK(&peers);
02199    } else {
02200       ast_db_deltree("dundi/cache", NULL);
02201       ast_cli(fd, "DUNDi Cache Flushed\n");
02202    }
02203    return RESULT_SUCCESS;
02204 }

static int dundi_helper struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  data,
int  flag
[static]
 

Definition at line 4219 of file pbx_dundi.c.

References ast_log(), ast_strlen_zero(), ast_test_flag, dundi_lookup(), ast_channel::exten, LOG_NOTICE, ast_channel::macroexten, MAX_RESULTS, and pbx_builtin_getvar_helper().

Referenced by dundi_canmatch(), dundi_exists(), and dundi_matchmore().

04220 {
04221    struct dundi_result results[MAX_RESULTS];
04222    int res;
04223    int x;
04224    int found = 0;
04225    if (!strncasecmp(context, "macro-", 6)) {
04226       if (!chan) {   
04227          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04228          return -1;
04229       }
04230       /* If done as a macro, use macro extension */
04231       if (!strcasecmp(exten, "s")) {
04232          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04233          if (ast_strlen_zero(exten))
04234             exten = chan->macroexten;
04235          if (ast_strlen_zero(exten))
04236             exten = chan->exten;
04237          if (ast_strlen_zero(exten)) { 
04238             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04239             return -1;
04240          }
04241       }
04242       if (ast_strlen_zero(data))
04243          data = "e164";
04244    } else {
04245       if (ast_strlen_zero(data))
04246          data = context;
04247    }
04248    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04249    for (x=0;x<res;x++) {
04250       if (ast_test_flag(results + x, flag))
04251          found++;
04252    }
04253    if (found >= priority)
04254       return 1;
04255    return 0;
04256 }

static void dundi_ie_append_eid_appropriately struct dundi_ie_data ied,
char *  context,
dundi_eid eid,
dundi_eid us
[static]
 

Definition at line 3014 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_eid_cmp(), dundi_ie_append_eid(), DUNDI_IE_EID, DUNDI_IE_EID_DIRECT, dundi_peer::eid, and has_permission().

Referenced by dundi_discover().

03015 {
03016    struct dundi_peer *p;
03017    if (!dundi_eid_cmp(eid, us)) {
03018       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03019       return;
03020    }
03021    AST_LIST_LOCK(&peers);
03022    AST_LIST_TRAVERSE(&peers, p, list) {
03023       if (!dundi_eid_cmp(&p->eid, eid)) {
03024          if (has_permission(&p->include, context))
03025             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03026          else
03027             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03028          break;
03029       }
03030    }
03031    if (!p)
03032       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03033    AST_LIST_UNLOCK(&peers);
03034 }

int dundi_lookup struct dundi_result result,
int  maxret,
struct ast_channel chan,
const char *  dcontext,
const char *  number,
int  cbypass
 

Lookup the given number in the given dundi context (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified. returns the number of results found or -1 on a hangup of teh channel.

Definition at line 3555 of file pbx_dundi.c.

References DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, and dundi_lookup_internal().

Referenced by dundi_do_lookup(), dundi_exec(), dundi_helper(), and dundifunc_read().

03556 {
03557    struct dundi_hint_metadata hmd;
03558    dundi_eid *avoid[1] = { NULL, };
03559    int direct[1] = { 0, };
03560    int expiration = dundi_cache_time;
03561    memset(&hmd, 0, sizeof(hmd));
03562    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03563    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03564 }

static int dundi_lookup_internal struct dundi_result result,
int  maxret,
struct ast_channel chan,
const char *  dcontext,
const char *  number,
int  ttl,
int  blockempty,
struct dundi_hint_metadata md,
int *  expiration,
int  cybpass,
int  modeselect,
dundi_eid skip,
dundi_eid avoid[],
int  direct[]
[static]
 

Definition at line 3451 of file pbx_dundi.c.

References ast_channel::_softhangup, abort_request(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), check_request(), discover_transactions(), dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, LOG_WARNING, optimize_transactions(), option_debug, register_request(), dundi_request::root_eid, and unregister_request().

Referenced by dundi_lookup().

03452 {
03453    int res;
03454    struct dundi_request dr, *pending;
03455    dundi_eid *rooteid=NULL;
03456    int x;
03457    int ttlms;
03458    int ms;
03459    int foundcache;
03460    int skipped=0;
03461    int order=0;
03462    char eid_str[20];
03463    struct timeval start;
03464    
03465    /* Don't do anthing for a hungup channel */
03466    if (chan && chan->_softhangup)
03467       return 0;
03468 
03469    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03470 
03471    for (x=0;avoid[x];x++)
03472       rooteid = avoid[x];
03473    /* Now perform real check */
03474    memset(&dr, 0, sizeof(dr));
03475    if (pipe(dr.pfds)) {
03476       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03477       return -1;
03478    }
03479    dr.dr = result;
03480    dr.hmd = hmd;
03481    dr.maxcount = maxret;
03482    dr.expiration = *expiration;
03483    dr.cbypass = cbypass;
03484    dr.crc32 = avoid_crc32(avoid);
03485    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03486    ast_copy_string(dr.number, number, sizeof(dr.number));
03487    if (rooteid)
03488       dr.root_eid = *rooteid;
03489    res = register_request(&dr, &pending);
03490    if (res) {
03491       /* Already a request */
03492       if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03493          /* This is on behalf of someone else.  Go ahead and close this out since
03494             they'll get their answer anyway. */
03495          if (option_debug)
03496             ast_log(LOG_DEBUG, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03497                dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03498          close(dr.pfds[0]);
03499          close(dr.pfds[1]);
03500          return -2;
03501       } else {
03502          /* Wait for the cache to populate */
03503          if (option_debug)
03504             ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n",
03505                dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03506          start = ast_tvnow();
03507          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03508             /* XXX Would be nice to have a way to poll/select here XXX */
03509             /* XXX this is a busy wait loop!!! */
03510             usleep(1);
03511          }
03512          /* Continue on as normal, our cache should kick in */
03513       }
03514    }
03515    /* Create transactions */
03516    do {
03517       order = skipped;
03518       skipped = 0;
03519       foundcache = 0;
03520       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03521    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03522    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03523       do this earlier because we didn't know if we were going to have transactions
03524       or not. */
03525    if (!ttl) {
03526       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03527       abort_request(&dr);
03528       unregister_request(&dr);
03529       close(dr.pfds[0]);
03530       close(dr.pfds[1]);
03531       return 0;
03532    }
03533       
03534    /* Optimize transactions */
03535    optimize_transactions(&dr, order);
03536    /* Actually perform transactions */
03537    discover_transactions(&dr);
03538    /* Wait for transaction to come back */
03539    start = ast_tvnow();
03540    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03541       ms = 100;
03542       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03543    }
03544    if (chan && chan->_softhangup && option_debug)
03545       ast_log(LOG_DEBUG, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03546    cancel_request(&dr);
03547    unregister_request(&dr);
03548    res = dr.respcount;
03549    *expiration = dr.expiration;
03550    close(dr.pfds[0]);
03551    close(dr.pfds[1]);
03552    return res;
03553 }

static int dundi_lookup_local struct dundi_result dr,
struct dundi_mapping map,
char *  called_number,
dundi_eid us_eid,
int  anscnt,
struct dundi_hint_metadata hmd
[static]
 

Definition at line 514 of file pbx_dundi.c.

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_exists_extension(), AST_FLAGS_ALL, ast_ignore_pattern(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_var_delete(), dr, dundi_eid_to_str(), DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, dundi_transaction::flags, map, pbx_substitute_variables_varshead(), tech2str(), and dundi_transaction::us_eid.

Referenced by dundi_lookup_thread(), and precache_trans().

00515 {
00516    struct ast_flags flags = {0};
00517    int x;
00518    if (!ast_strlen_zero(map->lcontext)) {
00519       if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00520          ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00521       if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00522          ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00523       if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00524          ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00525       if (ast_ignore_pattern(map->lcontext, called_number))
00526          ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00527 
00528       /* Clearly we can't say 'don't ask' anymore if we found anything... */
00529       if (ast_test_flag(&flags, AST_FLAGS_ALL)) 
00530          ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00531 
00532       if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00533          /* Skip partial answers */
00534          ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00535       }
00536       if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00537          struct varshead headp;
00538          struct ast_var_t *newvariable;
00539          ast_set_flag(&flags, map->options & 0xffff);
00540          ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00541          dr[anscnt].techint = map->tech;
00542          dr[anscnt].weight = map->weight;
00543          dr[anscnt].expiration = dundi_cache_time;
00544          ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00545          dr[anscnt].eid = *us_eid;
00546          dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00547          if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00548             AST_LIST_HEAD_INIT_NOLOCK(&headp);
00549             newvariable = ast_var_assign("NUMBER", called_number);
00550             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00551             newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
00552             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00553             newvariable = ast_var_assign("SECRET", cursecret);
00554             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00555             newvariable = ast_var_assign("IPADDR", ipaddr);
00556             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00557             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00558             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00559                ast_var_delete(newvariable);
00560          } else
00561             dr[anscnt].dest[0] = '\0';
00562          anscnt++;
00563       } else {
00564          /* No answers...  Find the fewest number of digits from the
00565             number for which we have no answer. */
00566          char tmp[AST_MAX_EXTENSION];
00567          for (x=0;x<AST_MAX_EXTENSION;x++) {
00568             tmp[x] = called_number[x];
00569             if (!tmp[x])
00570                break;
00571             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00572                /* Oops found something we can't match.  If this is longer
00573                   than the running hint, we have to consider it */
00574                if (strlen(tmp) > strlen(hmd->exten)) {
00575                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00576                }
00577                break;
00578             }
00579          }
00580       }
00581    }
00582    return anscnt;
00583 }

static void* dundi_lookup_thread void *  data  )  [static]
 

Definition at line 587 of file pbx_dundi.c.

References ast_log(), dundi_query_state::called_context, dundi_query_state::called_number, dr, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_lookup_local(), dundi_query_state::eids, LOG_DEBUG, dundi_query_state::maps, MAX_RESULTS, dundi_query_state::nummaps, option_debug, dundi_query_state::trans, and dundi_transaction::us_eid.

Referenced by dundi_answer_query().

00588 {
00589    struct dundi_query_state *st = data;
00590    struct dundi_result dr[MAX_RESULTS];
00591    struct dundi_ie_data ied;
00592    struct dundi_hint_metadata hmd;
00593    char eid_str[20];
00594    int res, x;
00595    int ouranswers=0;
00596    int max = 999999;
00597    int expiration = dundi_cache_time;
00598 
00599    if (option_debug)
00600       ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00601          st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00602    memset(&ied, 0, sizeof(ied));
00603    memset(&dr, 0, sizeof(dr));
00604    memset(&hmd, 0, sizeof(hmd));
00605    /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
00606    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00607    for (x=0;x<st->nummaps;x++)
00608       ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00609    if (ouranswers < 0)
00610       ouranswers = 0;
00611    for (x=0;x<ouranswers;x++) {
00612       if (dr[x].weight < max)
00613          max = dr[x].weight;
00614    }
00615       
00616    if (max) {
00617       /* If we do not have a canonical result, keep looking */
00618       res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs);
00619       if (res > 0) {
00620          /* Append answer in result */
00621          ouranswers += res;
00622       } else {
00623          if ((res < -1) && (!ouranswers))
00624             dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00625       }
00626    }
00627    AST_LIST_LOCK(&peers);
00628    /* Truncate if "don't ask" isn't present */
00629    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00630       hmd.exten[0] = '\0';
00631    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00632       if (option_debug)
00633          ast_log(LOG_DEBUG, "Our transaction went away!\n");
00634       st->trans->thread = 0;
00635       destroy_trans(st->trans, 0);
00636    } else {
00637       for (x=0;x<ouranswers;x++) {
00638          /* Add answers */
00639          if (dr[x].expiration && (expiration > dr[x].expiration))
00640             expiration = dr[x].expiration;
00641          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00642       }
00643       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00644       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00645       dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00646       st->trans->thread = 0;
00647    }
00648    AST_LIST_UNLOCK(&peers);
00649    free(st);
00650    return NULL;   
00651 }

static int dundi_matchmore struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data
[static]
 

Definition at line 4323 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04324 {
04325    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04326 }

static int dundi_no_debug int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2206 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02207 {
02208    if (argc != 3)
02209       return RESULT_SHOWUSAGE;
02210    dundidebug = 0;
02211    ast_cli(fd, "DUNDi Debugging Disabled\n");
02212    return RESULT_SUCCESS;
02213 }

static int dundi_no_store_history int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 2215 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02216 {
02217    if (argc != 4)
02218       return RESULT_SHOWUSAGE;
02219    global_storehistory = 0;
02220    ast_cli(fd, "DUNDi History Storage Disabled\n");
02221    return RESULT_SUCCESS;
02222 }

int dundi_precache const char *  context,
const char *  number
 

Pre-cache to push upstream peers.

Definition at line 3697 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03698 {
03699    dundi_eid *avoid[1] = { NULL, };
03700    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03701 }

static void dundi_precache_full void   )  [static]
 

Definition at line 3602 of file pbx_dundi.c.

References ast_get_context_name(), ast_get_extension_name(), AST_LIST_TRAVERSE, ast_lock_context(), ast_lock_contexts(), ast_log(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_context_extensions(), ast_walk_contexts(), dundi_mapping::dcontext, dundi_mapping::lcontext, LOG_NOTICE, and reschedule_precache().

Referenced by set_config().

03603 {
03604    struct dundi_mapping *cur;
03605    struct ast_context *con;
03606    struct ast_exten *e;
03607 
03608    AST_LIST_TRAVERSE(&mappings, cur, list) {
03609       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03610       ast_lock_contexts();
03611       con = NULL;
03612       while ((con = ast_walk_contexts(con))) {
03613          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03614             continue;
03615          /* Found the match, now queue them all up */
03616          ast_lock_context(con);
03617          e = NULL;
03618          while ((e = ast_walk_context_extensions(con, e)))
03619             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03620          ast_unlock_context(con);
03621       }
03622       ast_unlock_contexts();
03623    }
03624 }

static int dundi_precache_internal const char *  context,
const char *  number,
int  ttl,
dundi_eid avoids[]
[static]
 

Definition at line 3626 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, LOG_NOTICE, MAX_RESULTS, optimize_transactions(), option_debug, precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

03627 {
03628    struct dundi_request dr;
03629    struct dundi_hint_metadata hmd;
03630    struct dundi_result dr2[MAX_RESULTS];
03631    struct timeval start;
03632    struct dundi_mapping *maps = NULL, *cur;
03633    int nummaps = 0;
03634    int foundanswers;
03635    int foundcache, skipped, ttlms, ms;
03636    if (!context)
03637       context = "e164";
03638    if (option_debug)
03639       ast_log(LOG_DEBUG, "Precache internal (%s@%s)!\n", number, context);
03640 
03641    AST_LIST_LOCK(&peers);
03642    AST_LIST_TRAVERSE(&mappings, cur, list) {
03643       if (!strcasecmp(cur->dcontext, context))
03644          nummaps++;
03645    }
03646    if (nummaps) {
03647       maps = alloca(nummaps * sizeof(*maps));
03648       nummaps = 0;
03649       if (maps) {
03650          AST_LIST_TRAVERSE(&mappings, cur, list) {
03651             if (!strcasecmp(cur->dcontext, context))
03652                maps[nummaps++] = *cur;
03653          }
03654       }
03655    }
03656    AST_LIST_UNLOCK(&peers);
03657    if (!nummaps || !maps)
03658       return -1;
03659    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03660    memset(&dr2, 0, sizeof(dr2));
03661    memset(&dr, 0, sizeof(dr));
03662    memset(&hmd, 0, sizeof(hmd));
03663    dr.dr = dr2;
03664    ast_copy_string(dr.number, number, sizeof(dr.number));
03665    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03666    dr.maxcount = MAX_RESULTS;
03667    dr.expiration = dundi_cache_time;
03668    dr.hmd = &hmd;
03669    dr.pfds[0] = dr.pfds[1] = -1;
03670    pipe(dr.pfds);
03671    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03672    optimize_transactions(&dr, 0);
03673    foundanswers = 0;
03674    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03675    if (foundanswers) {
03676       if (dr.expiration > 0) 
03677          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03678       else
03679          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03680    }
03681    start = ast_tvnow();
03682    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03683       if (dr.pfds[0] > -1) {
03684          ms = 100;
03685          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03686       } else
03687          usleep(1);
03688    }
03689    cancel_request(&dr);
03690    if (dr.pfds[0] > -1) {
03691       close(dr.pfds[0]);
03692       close(dr.pfds[1]);
03693    }
03694    return 0;
03695 }

static void* dundi_precache_thread void *  data  )  [static]
 

Definition at line 653 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_PRECACHERP, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, dundi_precache_internal(), dundi_send(), dundi_query_state::eids, dundi_hint_metadata::exten, FLAG_DEAD, free, LOG_DEBUG, option_debug, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

00654 {
00655    struct dundi_query_state *st = data;
00656    struct dundi_ie_data ied;
00657    struct dundi_hint_metadata hmd;
00658    char eid_str[20];
00659 
00660    if (option_debug)
00661       ast_log(LOG_DEBUG, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00662          st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00663    memset(&ied, 0, sizeof(ied));
00664 
00665    /* Now produce precache */
00666    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00667 
00668    AST_LIST_LOCK(&peers);
00669    /* Truncate if "don't ask" isn't present */
00670    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00671       hmd.exten[0] = '\0';
00672    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00673       if (option_debug)
00674          ast_log(LOG_DEBUG, "Our transaction went away!\n");
00675       st->trans->thread = 0;
00676       destroy_trans(st->trans, 0);
00677    } else {
00678       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00679       st->trans->thread = 0;
00680    }
00681    AST_LIST_UNLOCK(&peers);
00682    free(st);
00683    return NULL;   
00684 }

static int dundi_prop_precache struct dundi_transaction trans,
struct dundi_ies