Wed Oct 28 13:33:17 2009

Asterisk developer's documentation


pbx_dundi.c File Reference

Distributed Universal Number Discovery (DUNDi). More...

#include "asterisk.h"
#include "asterisk/network.h"
#include <sys/ioctl.h>
#include <zlib.h>
#include <sys/signal.h>
#include <pthread.h>
#include <net/if.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.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/netsock.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/aes.h"
#include "asterisk/app.h"
#include "dundi-parser.h"

Include dependency graph for pbx_dundi.c:

Go to the source code of this file.

Data Structures

struct  alltrans
struct  dundi_hint_metadata
struct  dundi_mapping
struct  dundi_packet
struct  dundi_peer
struct  dundi_peer::permissionlist
struct  dundi_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_result_datastore
struct  dundi_transaction
struct  dundi_transaction::packetlist
struct  mappings
struct  pcq
struct  peers
struct  permission
struct  requests

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 %-7s %-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
#define MAX_WEIGHT   59999

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)
}
enum  { OPT_BYPASS_CACHE = (1 << 0) }

Functions

static void __reg_module (void)
static void __unreg_module (void)
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, const 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 unsigned long avoid_crc32 (dundi_eid *avoid[])
static void build_iv (unsigned char *iv)
static void build_mapping (const char *name, const 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, uint32_t 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, uint32_t keycrc32)
static void check_password (void)
static int check_request (struct dundi_request *dr)
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, ast_aes_decrypt_key *dcx)
static void deep_copy_peer (struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
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 (const void *data)
static int do_qualify (const void *data)
static int do_register (const void *data)
static int do_register_expire (const void *data)
static void drds_destroy (struct dundi_result_datastore *drds)
static void drds_destroy_cb (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 char * dundi_do_lookup (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_do_precache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_do_query (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 char * dundi_flush (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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. Lookup number in a given dundi context (if unspecified use e164), the given callerid (if specified) and return up to maxret results in the array specified.
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)
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 int dundi_query_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static void * dundi_query_thread (void *data)
static void dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin)
static int dundi_result_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int dundi_rexmit (const void *data)
static int dundi_send (struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
static char * dundi_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_entityid (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_mappings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_peer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_peers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_precache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_requests (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_trans (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_store_history (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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, ast_aes_encrypt_key *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_mapping_weight (struct dundi_mapping *map)
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_clearcache (void *ignore)
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 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, int reload)
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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Distributed Universal Number Discovery (DUNDi)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct dundi_peerany_peer
 Wildcard peer.
static struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 0
static pthread_t clearcachethreadid = AST_PTHREADT_NULL
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
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_custom_function dundi_query_function
static struct ast_app_option dundi_query_opts [128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, }
static struct ast_datastore_info dundi_result_datastore_info
static struct ast_custom_function dundi_result_function
static unsigned int dundi_result_id
static int dundi_shutdown = 0
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 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 int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char org [80]
static char phone [80]
static pthread_t precachethreadid = AST_PTHREADT_NULL
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static char stateprov [80]
static unsigned int tos = 0


Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 91 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 74 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 75 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 76 of file pbx_dundi.c.

Referenced by build_peer(), and model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 96 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 79 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 %-7s %-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 4161 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 70 of file pbx_dundi.c.

Referenced by handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 68 of file pbx_dundi.c.

#define MAX_WEIGHT   59999

Definition at line 72 of file pbx_dundi.c.

Referenced by build_mapping(), and get_mapping_weight().


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 81 of file pbx_dundi.c.

00081      {
00082    FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
00083    FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
00084    FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
00085    FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
00086    FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
00087    FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
00088    FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
00089 };

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3805 of file pbx_dundi.c.

03805      {
03806    OPT_BYPASS_CACHE = (1 << 0),
03807 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4827 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4827 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3362 of file pbx_dundi.c.

References AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, destroy_trans(), and dundi_request::trans.

Referenced by dundi_lookup_internal().

03363 {
03364    struct dundi_transaction *trans;
03365 
03366    AST_LIST_LOCK(&peers);
03367    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03368       /* This will remove the transaction from the list */
03369       destroy_trans(trans, 0);
03370    }
03371    AST_LIST_UNLOCK(&peers);
03372 }

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

Definition at line 1916 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(), dundi_packet::h, dundi_transaction::lasttrans, LOG_WARNING, dundi_hdr::oseqno, and dundi_transaction::packets.

Referenced by handle_frame().

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

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

Definition at line 4148 of file pbx_dundi.c.

References permission::allow, ast_calloc, AST_LIST_INSERT_TAIL, and permission::name.

Referenced by build_peer().

04149 {
04150    struct permission *perm;
04151 
04152    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04153       return;
04154 
04155    strcpy(perm->name, s);
04156    perm->allow = allow;
04157 
04158    AST_LIST_INSERT_TAIL(permlist, perm, list);
04159 }

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

Definition at line 3317 of file pbx_dundi.c.

References dundi_peer::addr, ast_debug, ast_eid_to_str(), AST_LIST_INSERT_HEAD, ast_strlen_zero(), create_transaction(), dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, dundi_peer::maxms, dundi_request::number, dundi_transaction::parent, dundi_request::query_eid, dundi_request::trans, and dundi_transaction::ttl.

Referenced by build_transactions().

03318 {
03319    struct dundi_transaction *trans;
03320    int x;
03321    char eid_str[20];
03322    char eid_str2[20];
03323 
03324    /* Ignore if not registered */
03325    if (!p->addr.sin_addr.s_addr)
03326       return 0;
03327    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03328       return 0;
03329 
03330    if (ast_strlen_zero(dr->number))
03331       ast_debug(1, "Will query peer '%s' for '%s' (context '%s')\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
03332    else
03333       ast_debug(1, "Will query peer '%s' for '%s@%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
03334 
03335    trans = create_transaction(p);
03336    if (!trans)
03337       return -1;
03338    trans->parent = dr;
03339    trans->ttl = ttl;
03340    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03341       trans->eids[x] = *avoid[x];
03342    trans->eidcount = x;
03343    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03344 
03345    return 0;
03346 }

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

Definition at line 1195 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_peer::inkey, dundi_peer::lastms, dundi_peer::maxms, dundi_transaction::retranstimer, dundi_transaction::them_eid, dundi_peer::us_eid, and dundi_transaction::us_eid.

Referenced by create_transaction(), and handle_command_response().

01196 {
01197    if (!trans->addr.sin_addr.s_addr)
01198       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01199    trans->us_eid = p->us_eid;
01200    trans->them_eid = p->eid;
01201    /* Enable encryption if appropriate */
01202    if (!ast_strlen_zero(p->inkey))
01203       ast_set_flag(trans, FLAG_ENCRYPT);
01204    if (p->maxms) {
01205       trans->autokilltimeout = p->maxms;
01206       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01207       if (p->lastms > 1) {
01208          trans->retranstimer = p->lastms * 2;
01209          /* Keep it from being silly */
01210          if (trans->retranstimer < 150)
01211             trans->retranstimer = 150;
01212       }
01213       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01214          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01215    } else
01216       trans->autokilltimeout = global_autokilltimeout;
01217 }

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

Definition at line 3483 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03484 {
03485    /* Idea is that we're calculating a checksum which is independent of
03486       the order that the EID's are listed in */
03487    uint32_t acrc32 = 0;
03488    int x;
03489    for (x=0;avoid[x];x++) {
03490       /* Order doesn't matter */
03491       if (avoid[x+1]) {
03492          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03493       }
03494    }
03495    return acrc32;
03496 }

static void build_iv ( unsigned char *  iv  )  [static]

Definition at line 445 of file pbx_dundi.c.

References ast_random().

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

00446 {
00447    /* XXX Would be nice to be more random XXX */
00448    unsigned int *fluffy;
00449    int x;
00450    fluffy = (unsigned int *)(iv);
00451    for (x=0;x<4;x++)
00452       fluffy[x] = ast_random();
00453 }

static void build_mapping ( const char *  name,
const char *  value 
) [static]

Definition at line 4163 of file pbx_dundi.c.

References dundi_mapping::_weight, ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdup, ast_strdupa, ast_strlen_zero(), dundi_mapping::dcontext, dundi_mapping::dead, dundi_mapping::dest, DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, dundi_mapping::lcontext, LOG_WARNING, map, MAX_OPTS, MAX_WEIGHT, dundi_mapping::options, str2tech(), dundi_mapping::tech, and dundi_mapping::weightstr.

Referenced by set_config().

04164 {
04165    char *t, *fields[MAX_OPTS];
04166    struct dundi_mapping *map;
04167    int x;
04168    int y;
04169 
04170    t = ast_strdupa(value);
04171 
04172    AST_LIST_TRAVERSE(&mappings, map, list) {
04173       /* Find a double match */
04174       if (!strcasecmp(map->dcontext, name) &&
04175          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) &&
04176            (!value[strlen(map->lcontext)] ||
04177             (value[strlen(map->lcontext)] == ','))))
04178          break;
04179    }
04180    if (!map) {
04181       if (!(map = ast_calloc(1, sizeof(*map))))
04182          return;
04183       AST_LIST_INSERT_HEAD(&mappings, map, list);
04184       map->dead = 1;
04185    }
04186    map->options = 0;
04187    memset(fields, 0, sizeof(fields));
04188    x = 0;
04189    while (t && x < MAX_OPTS) {
04190       fields[x++] = t;
04191       t = strchr(t, ',');
04192       if (t) {
04193          *t = '\0';
04194          t++;
04195       }
04196    } /* Russell was here, arrrr! */
04197    if ((x == 1) && ast_strlen_zero(fields[0])) {
04198       /* Placeholder mapping */
04199       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04200       map->dead = 0;
04201    } else if (x >= 4) {
04202       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04203       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04204       if ((sscanf(fields[1], "%30d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) {
04205          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04206          if ((map->tech = str2tech(fields[2])))
04207             map->dead = 0;
04208       } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') {
04209          map->weightstr = ast_strdup(fields[1]);
04210          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04211          if ((map->tech = str2tech(fields[2])))
04212             map->dead = 0;
04213       } else {
04214          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04215       }
04216       for (y = 4;y < x; y++) {
04217          if (!strcasecmp(fields[y], "nounsolicited"))
04218             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04219          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04220             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04221          else if (!strcasecmp(fields[y], "residential"))
04222             map->options |= DUNDI_FLAG_RESIDENTIAL;
04223          else if (!strcasecmp(fields[y], "commercial"))
04224             map->options |= DUNDI_FLAG_COMMERCIAL;
04225          else if (!strcasecmp(fields[y], "mobile"))
04226             map->options |= DUNDI_FLAG_MOBILE;
04227          else if (!strcasecmp(fields[y], "nopartial"))
04228             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04229          else
04230             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04231       }
04232    } else
04233       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04234 }

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

Definition at line 4318 of file pbx_dundi.c.

References dundi_peer::addr, append_permission(), ast_calloc, ast_copy_string(), ast_eid_cmp(), ast_eid_to_str(), ast_gethostbyname(), AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_str_to_eid(), ast_true(), dundi_peer::dead, DEFAULT_MAXMS, destroy_permissions(), do_register(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_MODEL_SYMMETRIC, DUNDI_PORT, dundi_peer::dynamic, dundi_peer::eid, hp, dundi_peer::include, dundi_peer::inkey, ast_variable::lineno, LOG_WARNING, dundi_peer::maxms, dundi_peer::model, ast_variable::name, ast_variable::next, dundi_peer::order, dundi_peer::outkey, dundi_peer::pcmodel, dundi_peer::permit, populate_addr(), qualify_peer(), dundi_peer::qualifyid, dundi_peer::registerexpire, dundi_peer::registerid, dundi_peer::us_eid, and ast_variable::value.

04319 {
04320    struct dundi_peer *peer;
04321    struct ast_hostent he;
04322    struct hostent *hp;
04323    dundi_eid testeid;
04324    int needregister=0;
04325    char eid_str[20];
04326 
04327    AST_LIST_LOCK(&peers);
04328    AST_LIST_TRAVERSE(&peers, peer, list) {
04329       if (!ast_eid_cmp(&peer->eid, eid)) {
04330          break;
04331       }
04332    }
04333    if (!peer) {
04334       /* Add us into the list */
04335       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04336          AST_LIST_UNLOCK(&peers);
04337          return;
04338       }
04339       peer->registerid = -1;
04340       peer->registerexpire = -1;
04341       peer->qualifyid = -1;
04342       peer->addr.sin_family = AF_INET;
04343       peer->addr.sin_port = htons(DUNDI_PORT);
04344       populate_addr(peer, eid);
04345       AST_LIST_INSERT_HEAD(&peers, peer, list);
04346    }
04347    peer->dead = 0;
04348    peer->eid = *eid;
04349    peer->us_eid = global_eid;
04350    destroy_permissions(&peer->permit);
04351    destroy_permissions(&peer->include);
04352    AST_SCHED_DEL(sched, peer->registerid);
04353    for (; v; v = v->next) {
04354       if (!strcasecmp(v->name, "inkey")) {
04355          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04356       } else if (!strcasecmp(v->name, "outkey")) {
04357          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04358       } else if (!strcasecmp(v->name, "host")) {
04359          if (!strcasecmp(v->value, "dynamic")) {
04360             peer->dynamic = 1;
04361          } else {
04362             hp = ast_gethostbyname(v->value, &he);
04363             if (hp) {
04364                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04365                peer->dynamic = 0;
04366             } else {
04367                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04368                peer->dead = 1;
04369             }
04370          }
04371       } else if (!strcasecmp(v->name, "ustothem")) {
04372          if (!ast_str_to_eid(&testeid, v->value))
04373             peer->us_eid = testeid;
04374          else
04375             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04376       } else if (!strcasecmp(v->name, "include")) {
04377          append_permission(&peer->include, v->value, 1);
04378       } else if (!strcasecmp(v->name, "permit")) {
04379          append_permission(&peer->permit, v->value, 1);
04380       } else if (!strcasecmp(v->name, "noinclude")) {
04381          append_permission(&peer->include, v->value, 0);
04382       } else if (!strcasecmp(v->name, "deny")) {
04383          append_permission(&peer->permit, v->value, 0);
04384       } else if (!strcasecmp(v->name, "register")) {
04385          needregister = ast_true(v->value);
04386       } else if (!strcasecmp(v->name, "order")) {
04387          if (!strcasecmp(v->value, "primary"))
04388             peer->order = 0;
04389          else if (!strcasecmp(v->value, "secondary"))
04390             peer->order = 1;
04391          else if (!strcasecmp(v->value, "tertiary"))
04392             peer->order = 2;
04393          else if (!strcasecmp(v->value, "quartiary"))
04394             peer->order = 3;
04395          else {
04396             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);
04397          }
04398       } else if (!strcasecmp(v->name, "qualify")) {
04399          if (!strcasecmp(v->value, "no")) {
04400             peer->maxms = 0;
04401          } else if (!strcasecmp(v->value, "yes")) {
04402             peer->maxms = DEFAULT_MAXMS;
04403          } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) {
04404             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n",
04405                ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04406             peer->maxms = 0;
04407          }
04408       } else if (!strcasecmp(v->name, "model")) {
04409          if (!strcasecmp(v->value, "inbound"))
04410             peer->model = DUNDI_MODEL_INBOUND;
04411          else if (!strcasecmp(v->value, "outbound"))
04412             peer->model = DUNDI_MODEL_OUTBOUND;
04413          else if (!strcasecmp(v->value, "symmetric"))
04414             peer->model = DUNDI_MODEL_SYMMETRIC;
04415          else if (!strcasecmp(v->value, "none"))
04416             peer->model = 0;
04417          else {
04418             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
04419                v->value, v->lineno);
04420          }
04421       } else if (!strcasecmp(v->name, "precache")) {
04422          if (!strcasecmp(v->value, "inbound"))
04423             peer->pcmodel = DUNDI_MODEL_INBOUND;
04424          else if (!strcasecmp(v->value, "outbound"))
04425             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04426          else if (!strcasecmp(v->value, "symmetric"))
04427             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04428          else if (!strcasecmp(v->value, "none"))
04429             peer->pcmodel = 0;
04430          else {
04431             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
04432                v->value, v->lineno);
04433          }
04434       }
04435    }
04436    (*globalpcmode) |= peer->pcmodel;
04437    if (!peer->model && !peer->pcmodel) {
04438       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n",
04439          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04440       peer->dead = 1;
04441    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04442       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n",
04443          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04444       peer->dead = 1;
04445    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04446       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n",
04447          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04448       peer->dead = 1;
04449    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04450       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n",
04451          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04452    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04453       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",
04454          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04455    } else {
04456       if (needregister) {
04457          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04458       }
04459       qualify_peer(peer, 1);
04460    }
04461    AST_LIST_UNLOCK(&peers);
04462 }

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

Definition at line 2006 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

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

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 3374 of file pbx_dundi.c.

References append_transaction(), ast_clear_flag_nonstd, ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, cache_lookup(), dundi_request::crc32, dundi_request::dcontext, dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, dundi_request::expiration, has_permission(), dundi_request::hmd, dundi_peer::include, dundi_peer::model, dundi_peer::order, pass, dundi_peer::pcmodel, dundi_peer::permit, and dundi_peer::us_eid.

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

03375 {
03376    struct dundi_peer *p;
03377    int x;
03378    int res;
03379    int pass;
03380    int allowconnect;
03381    char eid_str[20];
03382    AST_LIST_LOCK(&peers);
03383    AST_LIST_TRAVERSE(&peers, p, list) {
03384       if (modeselect == 1) {
03385          /* Send the precache to push upstreams only! */
03386          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03387          allowconnect = 1;
03388       } else {
03389          /* Normal lookup / EID query */
03390          pass = has_permission(&p->include, dr->dcontext);
03391          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03392       }
03393       if (skip) {
03394          if (!ast_eid_cmp(skip, &p->eid))
03395             pass = 0;
03396       }
03397       if (pass) {
03398          if (p->order <= order) {
03399             /* Check order first, then check cache, regardless of
03400                omissions, this gets us more likely to not have an
03401                affected answer. */
03402             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03403                res = 0;
03404                /* Make sure we haven't already seen it and that it won't
03405                   affect our answer */
03406                for (x=0;avoid[x];x++) {
03407                   if (!ast_eid_cmp(avoid[x], &p->eid) || !ast_eid_cmp(avoid[x], &p->us_eid)) {
03408                      /* If not a direct connection, it affects our answer */
03409                      if (directs && !directs[x])
03410                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03411                      break;
03412                   }
03413                }
03414                /* Make sure we can ask */
03415                if (allowconnect) {
03416                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03417                      /* Check for a matching or 0 cache entry */
03418                      append_transaction(dr, p, ttl, avoid);
03419                   } else {
03420                      ast_debug(1, "Avoiding '%s' in transaction\n", ast_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03421                   }
03422                }
03423             }
03424             *foundcache |= res;
03425          } else if (!*skipped || (p->order < *skipped))
03426             *skipped = p->order;
03427       }
03428    }
03429    AST_LIST_UNLOCK(&peers);
03430 }

static int cache_lookup ( struct dundi_request req,
dundi_eid peer_eid,
uint32_t  crc32,
int *  lowexpiration 
) [static]

Definition at line 1143 of file pbx_dundi.c.

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

Referenced by build_transactions().

01144 {
01145    char key[256];
01146    char eid_str[20];
01147    char eidroot_str[20];
01148    time_t now;
01149    int res=0;
01150    int res2=0;
01151    char eid_str_full[20];
01152    char tmp[256]="";
01153    int x;
01154 
01155    time(&now);
01156    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01157    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01158    ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01159    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32);
01160    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01161    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, 0);
01162    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01163    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01164    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01165    x = 0;
01166    if (!req->respcount) {
01167       while(!res2) {
01168          /* Look and see if we have a hint that would preclude us from looking at this
01169             peer for this number. */
01170          if (!(tmp[x] = req->number[x]))
01171             break;
01172          x++;
01173          /* Check for hints */
01174          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32);
01175          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01176          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, 0);
01177          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01178          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01179          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01180          if (res2) {
01181             if (strlen(tmp) > strlen(req->hmd->exten)) {
01182                /* Update meta data if appropriate */
01183                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01184             }
01185          }
01186       }
01187       res |= res2;
01188    }
01189 
01190    return res;
01191 }

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

Definition at line 1071 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_db_del(), ast_db_get(), ast_debug, ast_eid_to_str(), AST_FLAGS_ALL, ast_get_time_t(), dundi_result::dest, dundi_request::dr, dundi_flags2str(), DUNDI_HINT_DONT_ASK, dundi_str_short_to_eid(), dundi_result::eid, dundi_result::eid_str, dundi_result::expiration, ast_flags::flags, dundi_request::hmd, dundi_request::respcount, dundi_result::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by cache_lookup().

01072 {
01073    char data[1024];
01074    char *ptr, *term, *src;
01075    int tech;
01076    struct ast_flags flags;
01077    int weight;
01078    int length;
01079    int z;
01080    char fs[256];
01081 
01082    /* Build request string */
01083    if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
01084       time_t timeout;
01085       ptr = data;
01086       if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
01087          int expiration = timeout - now;
01088          if (expiration > 0) {
01089             ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
01090             ptr += length + 1;
01091             while((sscanf(ptr, "%30d/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) == 3)) {
01092                ptr += length;
01093                term = strchr(ptr, '|');
01094                if (term) {
01095                   *term = '\0';
01096                   src = strrchr(ptr, '/');
01097                   if (src) {
01098                      *src = '\0';
01099                      src++;
01100                   } else
01101                      src = "";
01102                   ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n",
01103                      tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
01104                   /* Make sure it's not already there */
01105                   for (z=0;z<req->respcount;z++) {
01106                      if ((req->dr[z].techint == tech) &&
01107                          !strcmp(req->dr[z].dest, ptr))
01108                            break;
01109                   }
01110                   if (z == req->respcount) {
01111                      /* Copy into parent responses */
01112                      ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);
01113                      req->dr[req->respcount].weight = weight;
01114                      req->dr[req->respcount].techint = tech;
01115                      req->dr[req->respcount].expiration = expiration;
01116                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
01117                      ast_eid_to_str(req->dr[req->respcount].eid_str,
01118                         sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
01119                      ast_copy_string(req->dr[req->respcount].dest, ptr,
01120                         sizeof(req->dr[req->respcount].dest));
01121                      ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
01122                         sizeof(req->dr[req->respcount].tech));
01123                      req->respcount++;
01124                      ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK);
01125                   } else if (req->dr[z].weight > weight)
01126                      req->dr[z].weight = weight;
01127                   ptr = term + 1;
01128                }
01129             }
01130             /* We found *something* cached */
01131             if (expiration < *lowexpiration)
01132                *lowexpiration = expiration;
01133             return 1;
01134          } else
01135             ast_db_del("dundi/cache", key);
01136       } else
01137          ast_db_del("dundi/cache", key);
01138    }
01139 
01140    return 0;
01141 }

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

Definition at line 800 of file pbx_dundi.c.

References ast_db_put(), 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.

Referenced by dundi_prop_precache(), and handle_command_response().

00801 {
00802    int x;
00803    char key1[256];
00804    char key2[256];
00805    char data[1024];
00806    char eidpeer_str[20];
00807    char eidroot_str[20];
00808    time_t timeout;
00809 
00810    if (expiration < 1)
00811       expiration = dundi_cache_time;
00812 
00813    /* Keep pushes a little longer, cut pulls a little short */
00814    if (push)
00815       expiration += 10;
00816    else
00817       expiration -= 10;
00818    if (expiration < 1)
00819       expiration = 1;
00820    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00821    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00822    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00823    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00824    /* Build request string */
00825    time(&timeout);
00826    timeout += expiration;
00827    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00828    for (x=start;x<req->respcount;x++) {
00829       /* Skip anything with an illegal pipe in it */
00830       if (strchr(req->dr[x].dest, '|'))
00831          continue;
00832       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|",
00833          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest,
00834          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00835    }
00836    ast_db_put("dundi/cache", key1, data);
00837    ast_db_put("dundi/cache", key2, data);
00838    return 0;
00839 }

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

Definition at line 765 of file pbx_dundi.c.

References ast_db_put(), ast_debug, 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, and dundi_request::root_eid.

Referenced by dundi_prop_precache(), and handle_command_response().

00766 {
00767    int unaffected;
00768    char key1[256];
00769    char key2[256];
00770    char eidpeer_str[20];
00771    char eidroot_str[20];
00772    char data[80];
00773    time_t timeout;
00774 
00775    if (expiration < 0)
00776       expiration = dundi_cache_time;
00777 
00778    /* Only cache hint if "don't ask" is there... */
00779    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))
00780       return 0;
00781 
00782    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00783 
00784    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00785    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00786    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00787    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00788 
00789    time(&timeout);
00790    timeout += expiration;
00791    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00792 
00793    ast_db_put("dundi/cache", key1, data);
00794    ast_debug(1, "Caching hint at '%s'\n", key1);
00795    ast_db_put("dundi/cache", key2, data);
00796    ast_debug(1, "Caching hint at '%s'\n", key2);
00797    return 0;
00798 }

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3348 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, DUNDI_COMMAND_CANCEL, dundi_send(), dundi_transaction::parent, and dundi_request::trans.

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03349 {
03350    struct dundi_transaction *trans;
03351 
03352    AST_LIST_LOCK(&peers);
03353    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03354       /* Orphan transaction from request */
03355       trans->parent = NULL;
03356       /* Send final cancel */
03357       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03358    }
03359    AST_LIST_UNLOCK(&peers);
03360 }

static int check_key ( struct dundi_peer peer,
unsigned char *  newkey,
unsigned char *  newsig,
uint32_t  keycrc32 
) [static]

Definition at line 1394 of file pbx_dundi.c.

References ast_aes_decrypt_key, ast_aes_encrypt_key, ast_check_signature_bin, ast_debug, ast_decrypt_bin, ast_eid_to_str(), ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_peer::eid, dundi_peer::inkey, LOG_NOTICE, dundi_peer::outkey, dundi_peer::rxenckey, dundi_peer::them_dcx, dundi_peer::them_ecx, and dundi_peer::them_keycrc32.

Referenced by handle_command_response().

01395 {
01396    unsigned char dst[128];
01397    int res;
01398    struct ast_key *key, *skey;
01399    char eid_str[20];
01400    ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32);
01401    if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
01402       /* A match */
01403       return 1;
01404    } else if (!newkey || !newsig)
01405       return 0;
01406    if (!memcmp(peer->rxenckey, newkey, 128) &&
01407        !memcmp(peer->rxenckey + 128, newsig, 128)) {
01408       /* By definition, a match */
01409       return 1;
01410    }
01411    /* Decrypt key */
01412    key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01413    if (!key) {
01414       ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
01415          peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01416       return -1;
01417    }
01418 
01419    skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01420    if (!skey) {
01421       ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
01422          peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01423       return -1;
01424    }
01425 
01426    /* First check signature */
01427    res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
01428    if (res)
01429       return 0;
01430 
01431    res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
01432    if (res != 16) {
01433       if (res >= 0)
01434          ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
01435       return 0;
01436    }
01437    /* Decrypted, passes signature */
01438    ast_debug(1, "Wow, new key combo passed signature and decrypt!\n");
01439    memcpy(peer->rxenckey, newkey, 128);
01440    memcpy(peer->rxenckey + 128, newsig, 128);
01441    peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
01442    ast_aes_decrypt_key(dst, &peer->them_dcx);
01443    ast_aes_encrypt_key(dst, &peer->them_ecx);
01444    return 1;
01445 }

static void check_password ( void   )  [static]

Definition at line 2073 of file pbx_dundi.c.

References ast_copy_string(), build_secret(), and save_secret().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3469 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

03470 {
03471    struct dundi_request *cur;
03472 
03473    AST_LIST_LOCK(&peers);
03474    AST_LIST_TRAVERSE(&requests, cur, list) {
03475       if (cur == dr)
03476          break;
03477    }
03478    AST_LIST_UNLOCK(&peers);
03479 
03480    return cur ? 1 : 0;
03481 }

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

Definition at line 2307 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

02308 {
02309    int which=0, len;
02310    char *ret = NULL;
02311    struct dundi_peer *p;
02312    char eid_str[20];
02313 
02314    if (pos != rpos)
02315       return NULL;
02316    AST_LIST_LOCK(&peers);
02317    len = strlen(word);
02318    AST_LIST_TRAVERSE(&peers, p, list) {
02319       const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02320       if (!strncasecmp(word, s, len) && ++which > state) {
02321          ret = ast_strdup(s);
02322          break;
02323       }
02324    }
02325    AST_LIST_UNLOCK(&peers);
02326    return ret;
02327 }

static struct dundi_transaction * create_transaction ( struct dundi_peer p  )  [static, read]

Definition at line 2824 of file pbx_dundi.c.

References dundi_peer::addr, apply_peer(), ast_calloc, AST_LIST_INSERT_HEAD, ast_set_flag, ast_tvnow(), dundi_transaction::autokillid, DUNDI_DEFAULT_RETRANS_TIMER, FLAG_SENDFULLKEY, FLAG_STOREHIST, get_trans_id(), dundi_transaction::retranstimer, dundi_peer::sentfullkey, dundi_transaction::start, and dundi_transaction::strans.

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

02825 {
02826    struct dundi_transaction *trans;
02827    int tid;
02828 
02829    /* Don't allow creation of transactions to non-registered peers */
02830    if (p && !p->addr.sin_addr.s_addr)
02831       return NULL;
02832    tid = get_trans_id();
02833    if (tid < 1)
02834       return NULL;
02835    if (!(trans = ast_calloc(1, sizeof(*trans))))
02836       return NULL;
02837 
02838    if (global_storehistory) {
02839       trans->start = ast_tvnow();
02840       ast_set_flag(trans, FLAG_STOREHIST);
02841    }
02842    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02843    trans->autokillid = -1;
02844    if (p) {
02845       apply_peer(trans, p);
02846       if (!p->sentfullkey)
02847          ast_set_flag(trans, FLAG_SENDFULLKEY);
02848    }
02849    trans->strans = tid;
02850    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02851 
02852    return trans;
02853 }

static int decrypt_memcpy ( unsigned char *  dst,
unsigned char *  src,
int  len,
unsigned char *  iv,
ast_aes_decrypt_key dcx 
) [static]

Definition at line 1286 of file pbx_dundi.c.

References ast_aes_decrypt.

Referenced by dundi_decrypt().

01287 {
01288    unsigned char lastblock[16];
01289    int x;
01290    memcpy(lastblock, iv, sizeof(lastblock));
01291    while(len > 0) {
01292       ast_aes_decrypt(src, dst, dcx);
01293       for (x=0;x<16;x++)
01294          dst[x] ^= lastblock[x];
01295       memcpy(lastblock, src, sizeof(lastblock));
01296       dst += 16;
01297       src += 16;
01298       len -= 16;
01299    }
01300    return 0;
01301 }

static void deep_copy_peer ( struct dundi_peer peer_dst,
const struct dundi_peer peer_src 
) [static]

Definition at line 1447 of file pbx_dundi.c.

References permission::allow, ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, dundi_peer::include, permission::name, and dundi_peer::permit.

Referenced by handle_command_response().

01448 {
01449    struct permission *cur, *perm;
01450 
01451    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01452 
01453    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01454    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01455 
01456    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01457       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01458          continue;
01459 
01460       perm->allow = cur->allow;
01461       strcpy(perm->name, cur->name);
01462 
01463       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01464    }
01465 
01466    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01467       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01468          continue;
01469 
01470       perm->allow = cur->allow;
01471       strcpy(perm->name, cur->name);
01472 
01473       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01474    }
01475 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4111 of file pbx_dundi.c.

References ast_free, and dundi_mapping::weightstr.

Referenced by prune_mappings().

04112 {
04113    if (map->weightstr)
04114       ast_free(map->weightstr);
04115    ast_free(map);
04116 }

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

Definition at line 2871 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE, AST_SCHED_DEL, dundi_transaction::packets, dundi_packet::parent, and dundi_packet::retransid.

Referenced by ack_trans().

02872 {
02873    if (pack->parent)
02874       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02875    AST_SCHED_DEL(sched, pack->retransid);
02876    if (needfree)
02877       ast_free(pack);
02878 }

static void destroy_packets ( struct packetlist *  p  )  [static]

Definition at line 1905 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, AST_SCHED_DEL, and dundi_packet::retransid.

Referenced by ack_trans(), destroy_trans(), and handle_frame().

01906 {
01907    struct dundi_packet *pack;
01908 
01909    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01910       AST_SCHED_DEL(sched, pack->retransid);
01911       ast_free(pack);
01912    }
01913 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

static void destroy_permissions ( struct permissionlist *  permlist  )  [static]

Definition at line 4092 of file pbx_dundi.c.

References ast_free, and AST_LIST_REMOVE_HEAD.

Referenced by build_peer(), and destroy_peer().

04093 {
04094    struct permission *perm;
04095 
04096    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04097       ast_free(perm);
04098 }

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

Definition at line 2880 of file pbx_dundi.c.

References ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_malloc, AST_SCHED_DEL, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), dundi_transaction::autokillid, dundi_peer::avgms, dundi_request::dcontext, destroy_packets(), DUNDI_TIMING_HISTORY, dundi_peer::eid, errno, FLAG_DEAD, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, dundi_peer::lastms, dundi_transaction::lasttrans, LOG_NOTICE, LOG_WARNING, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::maxms, dundi_request::number, dundi_transaction::packets, dundi_transaction::parent, dundi_request::pfds, dundi_peer::qualtrans, dundi_peer::qualtx, dundi_peer::regtrans, dundi_transaction::start, dundi_transaction::them_eid, dundi_transaction::thread, and dundi_request::trans.

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

02881 {
02882    struct dundi_peer *peer;
02883    int ms;
02884    int x;
02885    int cnt;
02886    char eid_str[20];
02887    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02888       AST_LIST_TRAVERSE(&peers, peer, list) {
02889          if (peer->regtrans == trans)
02890             peer->regtrans = NULL;
02891          if (peer->qualtrans == trans) {
02892             if (fromtimeout) {
02893                if (peer->lastms > -1)
02894                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02895                peer->lastms = -1;
02896             } else {
02897                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02898                if (ms < 1)
02899                   ms = 1;
02900                if (ms < peer->maxms) {
02901                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02902                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02903                } else if (peer->lastms < peer->maxms) {
02904                   ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
02905                }
02906                peer->lastms = ms;
02907             }
02908             peer->qualtrans = NULL;
02909          }
02910          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02911             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02912                if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) {
02913                   peer->avgms = 0;
02914                   cnt = 0;
02915                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02916                      ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02917                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02918                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02919                      peer->lookups[x] = peer->lookups[x-1];
02920                      if (peer->lookups[x]) {
02921                         peer->avgms += peer->lookuptimes[x];
02922                         cnt++;
02923                      }
02924                   }
02925                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
02926                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
02927                   if (peer->lookups[0]) {
02928                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
02929                      peer->avgms += peer->lookuptimes[0];
02930                      cnt++;
02931                   }
02932                   if (cnt)
02933                      peer->avgms /= cnt;
02934                }
02935             }
02936          }
02937       }
02938    }
02939    if (trans->parent) {
02940       /* Unlink from parent if appropriate */
02941       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
02942       if (AST_LIST_EMPTY(&trans->parent->trans)) {
02943          /* Wake up sleeper */
02944          if (trans->parent->pfds[1] > -1) {
02945             if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
02946                ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02947             }
02948          }
02949       }
02950    }
02951    /* Unlink from all trans */
02952    AST_LIST_REMOVE(&alltrans, trans, all);
02953    destroy_packets(&trans->packets);
02954    destroy_packets(&trans->lasttrans);
02955    AST_SCHED_DEL(sched, trans->autokillid);
02956    if (trans->thread) {
02957       /* If used by a thread, mark as dead and be done */
02958       ast_set_flag(trans, FLAG_DEAD);
02959    } else
02960       ast_free(trans);
02961 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3202 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_discover(), and dundi_request::trans.

Referenced by dundi_lookup_internal().

03203 {
03204    struct dundi_transaction *trans;
03205    AST_LIST_LOCK(&peers);
03206    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03207       dundi_discover(trans);
03208    }
03209    AST_LIST_UNLOCK(&peers);
03210    return 0;
03211 }

static int do_autokill ( const void *  data  )  [static]

Definition at line 3057 of file pbx_dundi.c.

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

Referenced by dundi_discover(), dundi_query(), and precache_trans().

03058 {
03059    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03060    char eid_str[20];
03061    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n",
03062       ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03063    trans->autokillid = -1;
03064    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03065    return 0;
03066 }

static int do_qualify ( const void *  data  )  [static]

Definition at line 4263 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04264 {
04265    struct dundi_peer *peer = (struct dundi_peer *)data;
04266    peer->qualifyid = -1;
04267    qualify_peer(peer, 0);
04268    return 0;
04269 }

static int do_register ( const void *  data  )  [static]

Definition at line 4237 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), destroy_trans(), DUNDI_COMMAND_REGREQ, DUNDI_DEFAULT_VERSION, 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, dundi_peer::registerid, dundi_peer::regtrans, dundi_transaction::us_eid, and dundi_peer::us_eid.

Referenced by build_peer().

04238 {
04239    struct dundi_ie_data ied;
04240    struct dundi_peer *peer = (struct dundi_peer *)data;
04241    char eid_str[20];
04242    char eid_str2[20];
04243    ast_debug(1, "Register us as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
04244    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04245    /* Destroy old transaction if there is one */
04246    if (peer->regtrans)
04247       destroy_trans(peer->regtrans, 0);
04248    peer->regtrans = create_transaction(peer);
04249    if (peer->regtrans) {
04250       ast_set_flag(peer->regtrans, FLAG_ISREG);
04251       memset(&ied, 0, sizeof(ied));
04252       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04253       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04254       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04255       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04256 
04257    } else
04258       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04259 
04260    return 0;
04261 }

static int do_register_expire ( const void *  data  )  [static]

Note:
Called with the peers list already locked

Definition at line 1220 of file pbx_dundi.c.

References dundi_peer::addr, ast_debug, ast_eid_to_str(), dundi_peer::eid, dundi_peer::lastms, and dundi_peer::registerexpire.

Referenced by handle_command_response(), and populate_addr().

01221 {
01222    struct dundi_peer *peer = (struct dundi_peer *)data;
01223    char eid_str[20];
01224    ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01225    peer->registerexpire = -1;
01226    peer->lastms = 0;
01227    memset(&peer->addr, 0, sizeof(peer->addr));
01228    return 0;
01229 }

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3888 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03889 {
03890    ast_free(drds);
03891 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3893 of file pbx_dundi.c.

References drds_destroy().

03894 {
03895    struct dundi_result_datastore *drds = data;
03896    drds_destroy(drds);
03897 }

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

Definition at line 363 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_command_response(), and handle_frame().

00364 {
00365    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00366 }

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

Definition at line 710 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, ast_log(), ast_pthread_create_detached, dundi_ies::called_context, dundi_query_state::called_context, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_EIDRESPONSE, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_query_thread(), dundi_send(), dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_query_state::fluffy, LOG_WARNING, dundi_ies::reqeid, dundi_query_state::reqeid, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

00711 {
00712    struct dundi_query_state *st;
00713    int totallen;
00714    int x;
00715    int skipfirst=0;
00716    char eid_str[20];
00717    char *s;
00718    pthread_t lookupthread;
00719 
00720    if (ies->eidcount > 1) {
00721       /* Since it is a requirement that the first EID is the authenticating host
00722          and the last EID is the root, it is permissible that the first and last EID
00723          could be the same.  In that case, we should go ahead copy only the "root" section
00724          since we will not need it for authentication. */
00725       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00726          skipfirst = 1;
00727    }
00728    totallen = sizeof(struct dundi_query_state);
00729    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00730    st = ast_calloc(1, totallen);
00731    if (st) {
00732       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00733       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00734       st->trans = trans;
00735       st->ttl = ies->ttl - 1;
00736       if (st->ttl < 0)
00737          st->ttl = 0;
00738       s = st->fluffy;
00739       for (x=skipfirst;ies->eids[x];x++) {
00740          st->eids[x-skipfirst] = (dundi_eid *)s;
00741          *st->eids[x-skipfirst] = *ies->eids[x];
00742          s += sizeof(dundi_eid);
00743       }
00744       ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00745 
00746       trans->thread = 1;
00747       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
00748          struct dundi_ie_data ied = { 0, };
00749          trans->thread = 0;
00750          ast_log(LOG_WARNING, "Unable to create thread!\n");
00751          ast_free(st);
00752          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00753          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00754          return -1;
00755       }
00756    } else {
00757       struct dundi_ie_data ied = { 0, };
00758       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00759       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00760       return -1;
00761    }
00762    return 0;
00763 }

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

Definition at line 988 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, dundi_ies::called_context, dundi_query_state::called_context, dundi_ies::called_number, dundi_query_state::called_number, dundi_ies::cbypass, dundi_mapping::dcontext, dundi_query_state::directs, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_DPRESPONSE, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_lookup_thread(), dundi_send(), dundi_ies::eid_direct, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_query_state::fluffy, dundi_mapping::list, LOG_WARNING, dundi_query_state::maps, dundi_mapping::next, dundi_query_state::nocache, dundi_query_state::nummaps, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

00989 {
00990    struct dundi_query_state *st;
00991    int totallen;
00992    int x;
00993    struct dundi_ie_data ied;
00994    char *s;
00995    struct dundi_mapping *cur;
00996    int mapcount = 0;
00997    int skipfirst = 0;
00998 
00999    pthread_t lookupthread;
01000    totallen = sizeof(struct dundi_query_state);
01001    /* Count matching map entries */
01002    AST_LIST_TRAVERSE(&mappings, cur, list) {
01003       if (!strcasecmp(cur->dcontext, ccontext))
01004          mapcount++;
01005    }
01006    /* If no maps, return -1 immediately */
01007    if (!mapcount)
01008       return -1;
01009 
01010    if (ies->eidcount > 1) {
01011       /* Since it is a requirement that the first EID is the authenticating host
01012          and the last EID is the root, it is permissible that the first and last EID
01013          could be the same.  In that case, we should go ahead copy only the "root" section
01014          since we will not need it for authentication. */
01015       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01016          skipfirst = 1;
01017    }
01018 
01019    totallen += mapcount * sizeof(struct dundi_mapping);
01020    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01021    st = ast_calloc(1, totallen);
01022    if (st) {
01023       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
01024       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01025       st->trans = trans;
01026       st->ttl = ies->ttl - 1;
01027       st->nocache = ies->cbypass;
01028       if (st->ttl < 0)
01029          st->ttl = 0;
01030       s = st->fluffy;
01031       for (x=skipfirst;ies->eids[x];x++) {
01032          st->eids[x-skipfirst] = (dundi_eid *)s;
01033          *st->eids[x-skipfirst] = *ies->eids[x];
01034          st->directs[x-skipfirst] = ies->eid_direct[x];
01035          s += sizeof(dundi_eid);
01036       }
01037       /* Append mappings */
01038       x = 0;
01039       st->maps = (struct dundi_mapping *)s;
01040       AST_LIST_TRAVERSE(&mappings, cur, list) {
01041          if (!strcasecmp(cur->dcontext, ccontext)) {
01042             if (x < mapcount) {
01043                st->maps[x] = *cur;
01044                st->maps[x].list.next = NULL;
01045                x++;
01046             }
01047          }
01048       }
01049       st->nummaps = mapcount;
01050       ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
01051       trans->thread = 1;
01052       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) {
01053          trans->thread = 0;
01054          ast_log(LOG_WARNING, "Unable to create thread!\n");
01055          ast_free(st);
01056          memset(&ied, 0, sizeof(ied));
01057          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01058          dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01059          return -1;
01060       }
01061    } else {
01062       ast_log(LOG_WARNING, "Out of memory!\n");
01063       memset(&ied, 0, sizeof(ied));
01064       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01065       dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01066       return -1;
01067    }
01068    return 0;
01069 }

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 4508 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04509 {
04510    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04511 }

static void dundi_debug_output ( const char *  data  )  [static]

Definition at line 270 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

00271 {
00272    if (dundidebug)
00273       ast_verbose("%s", data);
00274 }

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, read]

Definition at line 1303 of file pbx_dundi.c.

References ast_debug, dundi_transaction::dcx, decrypt_memcpy(), dundi_encblock::encdata, and dundi_encblock::iv.

Referenced by handle_command_response().

01304 {
01305    int space = *dstlen;
01306    unsigned long bytes;
01307    struct dundi_hdr *h;
01308    unsigned char *decrypt_space;
01309    decrypt_space = alloca(srclen);
01310    if (!decrypt_space)
01311       return NULL;
01312    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01313    /* Setup header */
01314    h = (struct dundi_hdr *)dst;
01315    *h = *ohdr;
01316    bytes = space - 6;
01317    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01318       ast_debug(1, "Ouch, uncompress failed :(\n");
01319       return NULL;
01320    }
01321    /* Update length */
01322    *dstlen = bytes + 6;
01323    /* Return new header */
01324    return h;
01325 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3090 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::cbypass, dundi_request::dcontext, 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, dundi_request::number, dundi_transaction::parent, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by discover_transactions().

03091 {
03092    struct dundi_ie_data ied;
03093    int x;
03094    if (!trans->parent) {
03095       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03096       return -1;
03097    }
03098    memset(&ied, 0, sizeof(ied));
03099    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03100    if (!dundi_eid_zero(&trans->us_eid))
03101       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03102    for (x=0;x<trans->eidcount;x++)
03103       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03104    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03105    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03106    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03107    if (trans->parent->cbypass)
03108       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03109    if (trans->autokilltimeout)
03110       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03111    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03112 }

static char* dundi_do_lookup ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2346 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_result::dest, dundi_flags2str(), dundi_lookup(), dundi_result::eid_str, dundi_result::expiration, ast_cli_args::fd, sort_results(), dundi_result::tech, ast_cli_entry::usage, and dundi_result::weight.

02347 {
02348    int res;
02349    char tmp[256];
02350    char fs[80] = "";
02351    char *context;
02352    int x;
02353    int bypass = 0;
02354    struct dundi_result dr[MAX_RESULTS];
02355    struct timeval start;
02356    switch (cmd) {
02357    case CLI_INIT:
02358       e->command = "dundi lookup";
02359       e->usage =
02360          "Usage: dundi lookup <number>[@context] [bypass]\n"
02361          "       Lookup the given number within the given DUNDi context\n"
02362          "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
02363          "keyword is specified.\n";
02364       return NULL;
02365    case CLI_GENERATE:
02366       return NULL;
02367    }
02368 
02369    if ((a->argc < 3) || (a->argc > 4))
02370       return CLI_SHOWUSAGE;
02371    if (a->argc > 3) {
02372       if (!strcasecmp(a->argv[3], "bypass"))
02373          bypass=1;
02374       else
02375          return CLI_SHOWUSAGE;
02376    }
02377    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02378    context = strchr(tmp, '@');
02379    if (context) {
02380       *context = '\0';
02381       context++;
02382    }
02383    start = ast_tvnow();
02384    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02385 
02386    if (res < 0)
02387       ast_cli(a->fd, "DUNDi lookup returned error.\n");
02388    else if (!res)
02389       ast_cli(a->fd, "DUNDi lookup returned no results.\n");
02390    else
02391       sort_results(dr, res);
02392    for (x=0;x<res;x++) {
02393       ast_cli(a->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));
02394       ast_cli(a->fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02395    }
02396    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02397    return CLI_SUCCESS;
02398 }

static char* dundi_do_precache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2400 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache(), ast_cli_args::fd, and ast_cli_entry::usage.

02401 {
02402    int res;
02403    char tmp[256];
02404    char *context;
02405    struct timeval start;
02406    switch (cmd) {
02407    case CLI_INIT:
02408       e->command = "dundi precache";
02409       e->usage =
02410          "Usage: dundi precache <number>[@context]\n"
02411          "       Lookup the given number within the given DUNDi context\n"
02412          "(or e164 if none is specified) and precaches the results to any\n"
02413          "upstream DUNDi push servers.\n";
02414       return NULL;
02415    case CLI_GENERATE:
02416       return NULL;
02417    }
02418    if ((a->argc < 3) || (a->argc > 3))
02419       return CLI_SHOWUSAGE;
02420    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02421    context = strchr(tmp, '@');
02422    if (context) {
02423       *context = '\0';
02424       context++;
02425    }
02426    start = ast_tvnow();
02427    res = dundi_precache(context, tmp);
02428 
02429    if (res < 0)
02430       ast_cli(a->fd, "DUNDi precache returned error.\n");
02431    else if (!res)
02432       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02433    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02434    return CLI_SUCCESS;
02435 }

static char* dundi_do_query ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2437 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_str_to_eid(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_entity_info::country, dundi_query_eid(), dundi_entity_info::email, ast_cli_args::fd, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, dundi_entity_info::stateprov, and ast_cli_entry::usage.

02438 {
02439    int res;
02440    char tmp[256];
02441    char *context;
02442    dundi_eid eid;
02443    struct dundi_entity_info dei;
02444    switch (cmd) {
02445    case CLI_INIT:
02446       e->command = "dundi query";
02447       e->usage =
02448          "Usage: dundi query <entity>[@context]\n"
02449          "       Attempts to retrieve contact information for a specific\n"
02450          "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
02451          "e164 if none is specified).\n";
02452       return NULL;
02453    case CLI_GENERATE:
02454       return NULL;
02455    }
02456    if ((a->argc < 3) || (a->argc > 3))
02457       return CLI_SHOWUSAGE;
02458    if (ast_str_to_eid(&eid, a->argv[2])) {
02459       ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
02460       return CLI_SHOWUSAGE;
02461    }
02462    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02463    context = strchr(tmp, '@');
02464    if (context) {
02465       *context = '\0';
02466       context++;
02467    }
02468    res = dundi_query_eid(&dei, context, eid);
02469    if (res < 0)
02470       ast_cli(a->fd, "DUNDi Query EID returned error.\n");
02471    else if (!res)
02472       ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
02473    else {
02474       ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
02475       ast_cli(a->fd, "Department:      %s\n", dei.orgunit);
02476       ast_cli(a->fd, "Organization:    %s\n", dei.org);
02477       ast_cli(a->fd, "City/Locality:   %s\n", dei.locality);
02478       ast_cli(a->fd, "State/Province:  %s\n", dei.stateprov);
02479       ast_cli(a->fd, "Country:         %s\n", dei.country);
02480       ast_cli(a->fd, "E-mail:          %s\n", dei.email);
02481       ast_cli(a->fd, "Phone:           %s\n", dei.phone);
02482       ast_cli(a->fd, "IP Address:      %s\n", dei.ipaddr);
02483    }
02484    return CLI_SUCCESS;
02485 }

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

Definition at line 1327 of file pbx_dundi.c.

References ast_debug, ast_log(), ast_set_flag, ast_test_flag, dundi_ie_data::buf, build_iv(), dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, 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, dundi_packet::h, dundi_hdr::ies, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_hdr::oseqno, dundi_ie_data::pos, dundi_peer::sentfullkey, dundi_transaction::them_eid, dundi_peer::txenckey, update_key(), dundi_peer::us_dcx, dundi_peer::us_ecx, dundi_transaction::us_eid, and dundi_peer::us_keycrc32.

Referenced by dundi_send().

01328 {
01329    unsigned char *compress_space;
01330    int len;
01331    int res;
01332    unsigned long bytes;
01333    struct dundi_ie_data ied;
01334    struct dundi_peer *peer;
01335    unsigned char iv[16];
01336    len = pack->datalen + pack->datalen / 100 + 42;
01337    compress_space = alloca(len);
01338    if (compress_space) {
01339       memset(compress_space, 0, len);
01340       /* We care about everthing save the first 6 bytes of header */
01341       bytes = len;
01342       res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
01343       if (res != Z_OK) {
01344          ast_debug(1, "Ouch, compression failed!\n");
01345          return -1;
01346       }
01347       memset(&ied, 0, sizeof(ied));
01348       /* Say who we are */
01349       if (!pack->h->iseqno && !pack->h->oseqno) {
01350          /* Need the key in the first copy */
01351          if (!(peer = find_peer(&trans->them_eid)))
01352             return -1;
01353          if (update_key(peer))
01354             return -1;
01355          if (!peer->sentfullkey)
01356             ast_set_flag(trans, FLAG_SENDFULLKEY);
01357          /* Append key data */
01358          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
01359          if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
01360             dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
01361             dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
01362          } else {
01363             dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
01364          }
01365          /* Setup contexts */
01366          trans->ecx = peer->us_ecx;
01367          trans->dcx = peer->us_dcx;
01368 
01369          /* We've sent the full key */
01370          peer->sentfullkey = 1;
01371       }
01372       /* Build initialization vector */
01373       build_iv(iv);
01374       /* Add the field, rounded up to 16 bytes */
01375       dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
01376       /* Copy the data */
01377       if ((ied.pos + bytes) >= sizeof(ied.buf)) {
01378          ast_log(LOG_NOTICE, "Final packet too large!\n");
01379          return -1;
01380       }
01381       encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
01382       ied.pos += ((bytes + 15) / 16) * 16;
01383       /* Reconstruct header */
01384       pack->datalen = sizeof(struct dundi_hdr);
01385       pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
01386       pack->h->cmdflags = 0;
01387       memcpy(pack->h->ies, ied.buf, ied.pos);
01388       pack->datalen += ied.pos;
01389       return 0;
01390    }
01391    return -1;
01392 }

static void dundi_error_output ( const char *  data  )  [static]

Definition at line 276 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00277 {
00278    ast_log(LOG_WARNING, "%s", data);
00279 }

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 4513 of file pbx_dundi.c.

References ast_log(), ast_strlen_zero(), ast_test_flag, DUNDI_FLAG_EXISTS, dundi_lookup(), ast_channel::exten, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), S_OR, and sort_results().

04514 {
04515    struct dundi_result results[MAX_RESULTS];
04516    int res;
04517    int x=0;
04518    char req[1024];
04519    const char *dundiargs;
04520    struct ast_app *dial;
04521 
04522    if (!strncasecmp(context, "macro-", 6)) {
04523       if (!chan) {
04524          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04525          return -1;
04526       }
04527       /* If done as a macro, use macro extension */
04528       if (!strcasecmp(exten, "s")) {
04529          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04530          if (ast_strlen_zero(exten))
04531             exten = chan->macroexten;
04532          if (ast_strlen_zero(exten))
04533             exten = chan->exten;
04534          if (ast_strlen_zero(exten)) {
04535             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04536             return -1;
04537          }
04538       }
04539       if (ast_strlen_zero(data))
04540          data = "e164";
04541    } else {
04542       if (ast_strlen_zero(data))
04543          data = context;
04544    }
04545    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04546    if (res > 0) {
04547       sort_results(results, res);
04548       for (x=0;x<res;x++) {
04549          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04550             if (!--priority)
04551                break;
04552          }
04553       }
04554    }
04555    if (x < res) {
04556       /* Got a hit! */
04557       dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
04558       snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest,
04559          S_OR(dundiargs, ""));
04560       dial = pbx_findapp("Dial");
04561       if (dial)
04562          res = pbx_exec(chan, dial, req);
04563    } else
04564       res = -1;
04565    return res;
04566 }

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 4503 of file pbx_dundi.c.

References DUNDI_FLAG_EXISTS, and dundi_helper().

04504 {
04505    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04506 }

static char* dundi_flush ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2248 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_db_deltree(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DUNDI_TIMING_HISTORY, ast_cli_args::fd, dundi_peer::lookups, dundi_peer::lookuptimes, and ast_cli_entry::usage.

02249 {
02250    int stats = 0;
02251    switch (cmd) {
02252    case CLI_INIT:
02253       e->command = "dundi flush [stats]";
02254       e->usage =
02255          "Usage: dundi flush [stats]\n"
02256          "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
02257          "'stats' is present, clears timer statistics instead of normal\n"
02258          "operation.\n";
02259       return NULL;
02260    case CLI_GENERATE:
02261       return NULL;
02262    }
02263    if ((a->argc < 2) || (a->argc > 3))
02264       return CLI_SHOWUSAGE;
02265    if (a->argc > 2) {
02266       if (!strcasecmp(a->argv[2], "stats"))
02267          stats = 1;
02268       else
02269          return CLI_SHOWUSAGE;
02270    }
02271    if (stats) {
02272       /* Flush statistics */
02273       struct dundi_peer *p;
02274       int x;
02275       AST_LIST_LOCK(&peers);
02276       AST_LIST_TRAVERSE(&peers, p, list) {
02277          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02278             if (p->lookups[x])
02279                ast_free(p->lookups[x]);
02280             p->lookups[x] = NULL;
02281             p->lookuptimes[x] = 0;
02282          }
02283          p->avgms = 0;
02284       }
02285       AST_LIST_UNLOCK(&peers);
02286    } else {
02287       ast_db_deltree("dundi/cache", NULL);
02288       ast_cli(a->fd, "DUNDi Cache Flushed\n");
02289    }
02290    return CLI_SUCCESS;
02291 }

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 4464 of file pbx_dundi.c.

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

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

04465 {
04466    struct dundi_result results[MAX_RESULTS];
04467    int res;
04468    int x;
04469    int found = 0;
04470    if (!strncasecmp(context, "macro-", 6)) {
04471       if (!chan) {
04472          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04473          return -1;
04474       }
04475       /* If done as a macro, use macro extension */
04476       if (!strcasecmp(exten, "s")) {
04477          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04478          if (ast_strlen_zero(exten))
04479             exten = chan->macroexten;
04480          if (ast_strlen_zero(exten))
04481             exten = chan->exten;
04482          if (ast_strlen_zero(exten)) {
04483             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04484             return -1;
04485          }
04486       }
04487       if (ast_strlen_zero(data))
04488          data = "e164";
04489    } else {
04490       if (ast_strlen_zero(data))
04491          data = context;
04492    }
04493    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04494    for (x=0;x<res;x++) {
04495       if (ast_test_flag(results + x, flag))
04496          found++;
04497    }
04498    if (found >= priority)
04499       return 1;
04500    return 0;
04501 }

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

Definition at line 3068 of file pbx_dundi.c.

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

Referenced by dundi_discover().

03069 {
03070    struct dundi_peer *p;
03071    if (!ast_eid_cmp(eid, us)) {
03072       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03073       return;
03074    }
03075    AST_LIST_LOCK(&peers);
03076    AST_LIST_TRAVERSE(&peers, p, list) {
03077       if (!ast_eid_cmp(&p->eid, eid)) {
03078          if (has_permission(&p->include, context))
03079             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03080          else
03081             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03082          break;
03083       }
03084    }
03085    if (!p)
03086       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03087    AST_LIST_UNLOCK(&peers);
03088 }

int dundi_lookup ( struct dundi_result result,
int  maxret,
struct ast_channel chan,
const char *  dcontext,
const char *  number,
int  nocache 
)

Lookup the given number in the given dundi context. Lookup number in a given dundi context (if unspecified use e164), the given callerid (if specified) and return up to maxret results in the array specified.

Return values:
the number of results found.
-1 on a hangup of the channel.

Definition at line 3600 of file pbx_dundi.c.

References DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_lookup_internal(), and dundi_hint_metadata::flags.

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

03601 {
03602    struct dundi_hint_metadata hmd;
03603    dundi_eid *avoid[1] = { NULL, };
03604    int direct[1] = { 0, };
03605    int expiration = dundi_cache_time;
03606    memset(&hmd, 0, sizeof(hmd));
03607    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03608    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03609 }

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 3498 of file pbx_dundi.c.

References abort_request(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), dundi_request::cbypass, check_request(), dundi_request::crc32, dundi_request::dcontext, discover_transactions(), dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_WARNING, dundi_request::maxcount, ast_channel::name, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, dundi_request::trans, and unregister_request().

Referenced by dundi_lookup(), dundi_lookup_thread(), and precache_trans().

03499 {
03500    int res;
03501    struct dundi_request dr, *pending;
03502    dundi_eid *rooteid=NULL;
03503    int x;
03504    int ttlms;
03505    int ms;
03506    int foundcache;
03507    int skipped=0;
03508    int order=0;
03509    char eid_str[20];
03510    struct timeval start;
03511 
03512    /* Don't do anthing for a hungup channel */
03513    if (chan && ast_check_hangup(chan))
03514       return 0;
03515 
03516    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03517 
03518    for (x=0;avoid[x];x++)
03519       rooteid = avoid[x];
03520    /* Now perform real check */
03521    memset(&dr, 0, sizeof(dr));
03522    if (pipe(dr.pfds)) {
03523       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03524       return -1;
03525    }
03526    dr.dr = result;
03527    dr.hmd = hmd;
03528    dr.maxcount = maxret;
03529    dr.expiration = *expiration;
03530    dr.cbypass = cbypass;
03531    dr.crc32 = avoid_crc32(avoid);
03532    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03533    ast_copy_string(dr.number, number, sizeof(dr.number));
03534    if (rooteid)
03535       dr.root_eid = *rooteid;
03536    res = register_request(&dr, &pending);
03537    if (res) {
03538       /* Already a request */
03539       if (rooteid && !ast_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03540          /* This is on behalf of someone else.  Go ahead and close this out since
03541             they'll get their answer anyway. */
03542          ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03543             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03544          close(dr.pfds[0]);
03545          close(dr.pfds[1]);
03546          return -2;
03547       } else {
03548          /* Wait for the cache to populate */
03549          ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n",
03550             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03551          start = ast_tvnow();
03552          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03553             /* XXX Would be nice to have a way to poll/select here XXX */
03554             /* XXX this is a busy wait loop!!! */
03555             usleep(1);
03556          }
03557          /* Continue on as normal, our cache should kick in */
03558       }
03559    }
03560    /* Create transactions */
03561    do {
03562       order = skipped;
03563       skipped = 0;
03564       foundcache = 0;
03565       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03566    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03567    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03568       do this earlier because we didn't know if we were going to have transactions
03569       or not. */
03570    if (!ttl) {
03571       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03572       abort_request(&dr);
03573       unregister_request(&dr);
03574       close(dr.pfds[0]);
03575       close(dr.pfds[1]);
03576       return 0;
03577    }
03578 
03579    /* Optimize transactions */
03580    optimize_transactions(&dr, order);
03581    /* Actually perform transactions */
03582    discover_transactions(&dr);
03583    /* Wait for transaction to come back */
03584    start = ast_tvnow();
03585    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03586       ms = 100;
03587       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03588    }
03589    if (chan && ast_check_hangup(chan))
03590       ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03591    cancel_request(&dr);
03592    unregister_request(&dr);
03593    res = dr.respcount;
03594    *expiration = dr.expiration;
03595    close(dr.pfds[0]);
03596    close(dr.pfds[1]);
03597    return res;
03598 }

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 485 of file pbx_dundi.c.

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_eid_to_str(), 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(), dundi_result::dest, dundi_mapping::dest, DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, dundi_result::eid, ast_var_t::entries, dundi_result::expiration, dundi_hint_metadata::exten, get_mapping_weight(), dundi_mapping::lcontext, dundi_mapping::options, pbx_substitute_variables_varshead(), dundi_result::tech, dundi_mapping::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by dundi_lookup_thread(), and precache_trans().

00486 {
00487    struct ast_flags flags = {0};
00488    int x;
00489    if (!ast_strlen_zero(map->lcontext)) {
00490       if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00491          ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00492       if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00493          ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00494       if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00495          ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00496       if (ast_ignore_pattern(map->lcontext, called_number))
00497          ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00498 
00499       /* Clearly we can't say 'don't ask' anymore if we found anything... */
00500       if (ast_test_flag(&flags, AST_FLAGS_ALL))
00501          ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00502 
00503       if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00504          /* Skip partial answers */
00505          ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00506       }
00507       if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00508          struct varshead headp;
00509          struct ast_var_t *newvariable;
00510          ast_set_flag(&flags, map->options & 0xffff);
00511          ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00512          dr[anscnt].techint = map->tech;
00513          dr[anscnt].weight = get_mapping_weight(map);
00514          dr[anscnt].expiration = dundi_cache_time;
00515          ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00516          dr[anscnt].eid = *us_eid;
00517          ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00518          if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00519             AST_LIST_HEAD_INIT_NOLOCK(&headp);
00520             newvariable = ast_var_assign("NUMBER", called_number);
00521             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00522             newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
00523             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00524             newvariable = ast_var_assign("SECRET", cursecret);
00525             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00526             newvariable = ast_var_assign("IPADDR", ipaddr);
00527             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00528             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00529             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00530                ast_var_delete(newvariable);
00531          } else
00532             dr[anscnt].dest[0] = '\0';
00533          anscnt++;
00534       } else {
00535          /* No answers...  Find the fewest number of digits from the
00536             number for which we have no answer. */
00537          char tmp[AST_MAX_EXTENSION + 1] = "";
00538          for (x = 0; x < (sizeof(tmp) - 1); x++) {
00539             tmp[x] = called_number[x];
00540             if (!tmp[x])
00541                break;
00542             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00543                /* Oops found something we can't match.  If this is longer
00544                   than the running hint, we have to consider it */
00545                if (strlen(tmp) > strlen(hmd->exten)) {
00546                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00547                }
00548                break;
00549             }
00550          }
00551       }
00552    }
00553    return anscnt;
00554 }

static void* dundi_lookup_thread ( void *  data  )  [static]

Definition at line 558 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), dundi_query_state::directs, DUNDI_CAUSE_DUPLICATE, DUNDI_COMMAND_DPRESPONSE, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_cause(), dundi_ie_append_hint(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_query_state::eids, dundi_result::expiration, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by dundi_answer_query().

00559 {
00560    struct dundi_query_state *st = data;
00561    struct dundi_result dr[MAX_RESULTS];
00562    struct dundi_ie_data ied;
00563    struct dundi_hint_metadata hmd;
00564    char eid_str[20];
00565    int res, x;
00566    int ouranswers=0;
00567    int max = 999999;
00568    int expiration = dundi_cache_time;
00569 
00570    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00571          st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00572    memset(&ied, 0, sizeof(ied));
00573    memset(&dr, 0, sizeof(dr));
00574    memset(&hmd, 0, sizeof(hmd));
00575    /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
00576    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00577    for (x=0;x<st->nummaps;x++)
00578       ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00579    if (ouranswers < 0)
00580       ouranswers = 0;
00581    for (x=0;x<ouranswers;x++) {
00582       if (dr[x].weight < max)
00583          max = dr[x].weight;
00584    }
00585 
00586    if (max) {
00587       /* If we do not have a canonical result, keep looking */
00588       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);
00589       if (res > 0) {
00590          /* Append answer in result */
00591          ouranswers += res;
00592       } else {
00593          if ((res < -1) && (!ouranswers))
00594             dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00595       }
00596    }
00597    AST_LIST_LOCK(&peers);
00598    /* Truncate if "don't ask" isn't present */
00599    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00600       hmd.exten[0] = '\0';
00601    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00602       ast_debug(1, "Our transaction went away!\n");
00603       st->trans->thread = 0;
00604       destroy_trans(st->trans, 0);
00605    } else {
00606       for (x=0;x<ouranswers;x++) {
00607          /* Add answers */
00608          if (dr[x].expiration && (expiration > dr[x].expiration))
00609             expiration = dr[x].expiration;
00610          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00611       }
00612       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00613       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00614       dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00615       st->trans->thread = 0;
00616    }
00617    AST_LIST_UNLOCK(&peers);
00618    ast_free(st);
00619    return NULL;
00620 }

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 4568 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04569 {
04570    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04571 }

int dundi_precache ( const char *  context,
const char *  number 
)

Pre-cache to push upstream peers.

Definition at line 3744 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03745 {
03746    dundi_eid *avoid[1] = { NULL, };
03747    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03748 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3647 of file pbx_dundi.c.

References ast_get_context_name(), ast_get_extension_name(), AST_LIST_TRAVERSE, ast_log(), ast_rdlock_context(), ast_rdlock_contexts(), 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().

03648 {
03649    struct dundi_mapping *cur;
03650    struct ast_context *con;
03651    struct ast_exten *e;
03652 
03653    AST_LIST_TRAVERSE(&mappings, cur, list) {
03654       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03655       ast_rdlock_contexts();
03656       con = NULL;
03657       while ((con = ast_walk_contexts(con))) {
03658          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03659             continue;
03660          /* Found the match, now queue them all up */
03661          ast_rdlock_context(con);
03662          e = NULL;
03663          while ((e = ast_walk_context_extensions(con, e)))
03664             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03665          ast_unlock_context(con);
03666       }
03667       ast_unlock_contexts();
03668    }
03669 }

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

Definition at line 3671 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dundi_request::dcontext, dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, precache_transactions(), reschedule_precache(), and dundi_request::trans.

Referenced by dundi_precache(), and dundi_precache_thread().

03672 {
03673    struct dundi_request dr;
03674    struct dundi_hint_metadata hmd;
03675    struct dundi_result dr2[MAX_RESULTS];
03676    struct timeval start;
03677    struct dundi_mapping *maps = NULL, *cur;
03678    int nummaps = 0;
03679    int foundanswers;
03680    int foundcache, skipped, ttlms, ms;
03681    if (!context)
03682       context = "e164";
03683    ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
03684 
03685    AST_LIST_LOCK(&peers);
03686    AST_LIST_TRAVERSE(&mappings, cur, list) {
03687       if (!strcasecmp(cur->dcontext, context))
03688          nummaps++;
03689    }
03690    if (nummaps) {
03691       maps = alloca(nummaps * sizeof(*maps));
03692       nummaps = 0;
03693       if (maps) {
03694          AST_LIST_TRAVERSE(&mappings, cur, list) {
03695             if (!strcasecmp(cur->dcontext, context))
03696                maps[nummaps++] = *cur;
03697          }
03698       }
03699    }
03700    AST_LIST_UNLOCK(&peers);
03701    if (!nummaps || !maps)
03702       return -1;
03703    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03704    memset(&dr2, 0, sizeof(dr2));
03705    memset(&dr, 0, sizeof(dr));
03706    memset(&hmd, 0, sizeof(hmd));
03707    dr.dr = dr2;
03708    ast_copy_string(dr.number, number, sizeof(dr.number));
03709    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03710    dr.maxcount = MAX_RESULTS;
03711    dr.expiration = dundi_cache_time;
03712    dr.hmd = &hmd;
03713    dr.pfds[0] = dr.pfds[1] = -1;
03714    if (pipe(dr.pfds) < 0) {
03715       ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno));
03716       return -1;
03717    }
03718    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03719    optimize_transactions(&dr, 0);
03720    foundanswers = 0;
03721    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03722    if (foundanswers) {
03723       if (dr.expiration > 0)
03724          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03725       else
03726          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03727    }
03728    start = ast_tvnow();
03729    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03730       if (dr.pfds[0] > -1) {
03731          ms = 100;
03732          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03733       } else
03734          usleep(1);
03735    }
03736    cancel_request(&dr);
03737    if (dr.pfds[0] > -1) {
03738       close(dr.pfds[0]);
03739       close(dr.pfds[1]);
03740    }
03741    return 0;
03742 }

static void* dundi_precache_thread ( void *  data  )  [static]

Definition at line 622 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_PRECACHERP, DUNDI_HINT_DONT_ASK, dundi_precache_internal(), dundi_send(), dundi_query_state::eids, dundi_hint_metadata::exten, FLAG_DEAD, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

Referenced by dundi_prop_precache().

00623 {
00624    struct dundi_query_state *st = data;
00625    struct dundi_ie_data ied;
00626    struct dundi_hint_metadata hmd;
00627    char eid_str[20];
00628 
00629    ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
00630       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00631    memset(&ied, 0, sizeof(ied));
00632 
00633    /* Now produce precache */
00634    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00635 
00636    AST_LIST_LOCK(&peers);
00637    /* Truncate if "don't ask" isn't present */
00638    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00639       hmd.exten[0] = '\0';
00640    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00641       ast_debug(1, "Our transaction went away!\n");
00642       st->trans->thread = 0;
00643       destroy_trans(st->trans, 0);
00644    } else {
00645       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00646       st->trans->thread = 0;
00647    }
00648    AST_LIST_UNLOCK(&peers);
00649    ast_free(st);
00650    return NULL;
00651 }

static int dundi_prop_precache ( struct dundi_transaction trans,
struct dundi_ies ies,
char *  ccontext 
) [static]

Definition at line 841 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, cache_save(), cache_save_hint(), dundi_query_state::called_context, dundi_ies::called_context, dundi_query_state::called_number, dundi_ies::called_number, dundi_ies::cbypass, dundi_answer::data, dundi_mapping::dcontext, dundi_request::dcontext, dundi_result::dest, dundi_query_state::directs, dundi_request::dr, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_PRECACHERP, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_precache_thread(), dundi_send(), dundi_answer::eid, dundi_result::eid, dundi_ies::eid_direct, dundi_result::eid_str, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_result::expiration, dundi_ies::expiration, dundi_request::expiration, dundi_answer::flags, dundi_result::flags, dundi_hint_metadata::flags, dundi_query_state::fluffy, dundi_ies::hint, dundi_request::hmd, dundi_mapping::list, LOG_NOTICE, LOG_WARNING, dundi_query_state::maps, dundi_request::maxcount, dundi_mapping::next, dundi_query_state::nocache, dundi_request::number, dundi_query_state::nummaps, dundi_transaction::parent, dundi_request::pfds, dundi_answer::protocol, dundi_request::respcount, s, dundi_result::tech, tech2str(), dundi_result::techint, dundi_transaction::them_eid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, dundi_query_state::ttl, dundi_answer::weight, and dundi_result::weight.

Referenced by handle_command_response().

00842 {
00843    struct dundi_query_state *st;
00844    int totallen;
00845    int x,z;
00846    struct dundi_ie_data ied;
00847    char *s;
00848    struct dundi_result dr2[MAX_RESULTS];
00849    struct dundi_request dr;
00850    struct dundi_hint_metadata hmd;
00851 
00852    struct dundi_mapping *cur;
00853    int mapcount;
00854    int skipfirst = 0;
00855 
00856    pthread_t lookupthread;
00857 
00858    memset(&dr2, 0, sizeof(dr2));
00859    memset(&dr, 0, sizeof(dr));
00860    memset(&hmd, 0, sizeof(hmd));
00861 
00862    /* Forge request structure to hold answers for cache */
00863    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00864    dr.dr = dr2;
00865    dr.maxcount = MAX_RESULTS;
00866    dr.expiration = dundi_cache_time;
00867    dr.hmd = &hmd;
00868    dr.pfds[0] = dr.pfds[1] = -1;
00869    trans->parent = &dr;
00870    ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
00871    ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
00872 
00873    for (x=0;x<ies->anscount;x++) {
00874       if (trans->parent->respcount < trans->parent->maxcount) {
00875          /* Make sure it's not already there */
00876          for (z=0;z<trans->parent->respcount;z++) {
00877             if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
00878                 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data))
00879                   break;
00880          }
00881          if (z == trans->parent->respcount) {
00882             /* Copy into parent responses */
00883             trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
00884             trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
00885             trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
00886             trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
00887             if (ies->expiration > 0)
00888                trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
00889             else
00890                trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
00891             ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
00892                sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
00893                &ies->answers[x]->eid);
00894             ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
00895                sizeof(trans->parent->dr[trans->parent->respcount].dest));
00896                ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
00897                sizeof(trans->parent->dr[trans->parent->respcount].tech));
00898             trans->parent->respcount++;
00899             ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
00900          } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
00901             /* Update weight if appropriate */
00902             trans->parent->dr[z].weight = ies->answers[x]->weight;
00903          }
00904       } else
00905          ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
00906             trans->parent->number, trans->parent->dcontext);
00907 
00908    }
00909    /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
00910    cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
00911    if (ies->hint)
00912       cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
00913 
00914    totallen = sizeof(struct dundi_query_state);
00915    /* Count matching map entries */
00916    mapcount = 0;
00917    AST_LIST_TRAVERSE(&mappings, cur, list) {
00918       if (!strcasecmp(cur->dcontext, ccontext))
00919          mapcount++;
00920    }
00921 
00922    /* If no maps, return -1 immediately */
00923    if (!mapcount)
00924       return -1;
00925 
00926    if (ies->eidcount > 1) {
00927       /* Since it is a requirement that the first EID is the authenticating host
00928          and the last EID is the root, it is permissible that the first and last EID
00929          could be the same.  In that case, we should go ahead copy only the "root" section
00930          since we will not need it for authentication. */
00931       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00932          skipfirst = 1;
00933    }
00934 
00935    /* Prepare to run a query and then propagate that as necessary */
00936    totallen += mapcount * sizeof(struct dundi_mapping);
00937    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00938    st = ast_calloc(1, totallen);
00939    if (st) {
00940       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00941       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
00942       st->trans = trans;
00943       st->ttl = ies->ttl - 1;
00944       st->nocache = ies->cbypass;
00945       if (st->ttl < 0)
00946          st->ttl = 0;
00947       s = st->fluffy;
00948       for (x=skipfirst;ies->eids[x];x++) {
00949          st->eids[x-skipfirst] = (dundi_eid *)s;
00950          *st->eids[x-skipfirst] = *ies->eids[x];
00951          st->directs[x-skipfirst] = ies->eid_direct[x];
00952          s += sizeof(dundi_eid);
00953       }
00954       /* Append mappings */
00955       x = 0;
00956       st->maps = (struct dundi_mapping *)s;
00957       AST_LIST_TRAVERSE(&mappings, cur, list) {
00958          if (!strcasecmp(cur->dcontext, ccontext)) {
00959             if (x < mapcount) {
00960                st->maps[x] = *cur;
00961                st->maps[x].list.next = NULL;
00962                x++;
00963             }
00964          }
00965       }
00966       st->nummaps = mapcount;
00967       ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
00968       trans->thread = 1;
00969       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
00970          trans->thread = 0;
00971          ast_log(LOG_WARNING, "Unable to create thread!\n");
00972          ast_free(st);
00973          memset(&ied, 0, sizeof(ied));
00974          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00975          dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00976          return -1;
00977       }
00978    } else {
00979       ast_log(LOG_WARNING, "Out of memory!\n");
00980       memset(&ied, 0, sizeof(ied));
00981       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00982       dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00983       return -1;
00984    }
00985    return 0;
00986 }

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3180 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, do_autokill(), DUNDI_COMMAND_EIDQUERY, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append_eid(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_EID, DUNDI_IE_REQEID, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, dundi_transaction::parent, dundi_request::query_eid, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by query_transactions().

03181 {
03182    struct dundi_ie_data ied;
03183    int x;
03184    if (!trans->parent) {
03185       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03186       return -1;
03187    }
03188    memset(&ied, 0, sizeof(ied));
03189    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03190    if (!dundi_eid_zero(&trans->us_eid))
03191       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03192    for (x=0;x<trans->eidcount;x++)
03193       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03194    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03195    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03196    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03197    if (trans->autokilltimeout)
03198       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03199    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03200 }

int dundi_query_eid ( struct dundi_entity_info dei,
const char *  dcontext,
dundi_eid  eid 
)

Retrieve information on a specific EID.

Definition at line 3797 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03798 {
03799    dundi_eid *avoid[1] = { NULL, };
03800    struct dundi_hint_metadata hmd;
03801    memset(&hmd, 0, sizeof(hmd));
03802    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03803 }

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]

Definition at line 3750 of file pbx_dundi.c.

References ast_copy_string(), AST_LIST_EMPTY, ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), build_transactions(), dundi_request::dcontext, dundi_request::dei, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, dundi_request::hmd, optimize_transactions(), dundi_request::pfds, dundi_request::query_eid, query_transactions(), dundi_request::respcount, dundi_request::root_eid, and dundi_request::trans.

Referenced by dundi_query_eid(), and dundi_query_thread().

03751 {
03752    int res;
03753    struct dundi_request dr;
03754    dundi_eid *rooteid=NULL;
03755    int x;
03756    int ttlms;
03757    int skipped=0;
03758    int foundcache=0;
03759    struct timeval start;
03760 
03761    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03762 
03763    for (x=0;avoid[x];x++)
03764       rooteid = avoid[x];
03765    /* Now perform real check */
03766    memset(&dr, 0, sizeof(dr));
03767    dr.hmd = hmd;
03768    dr.dei = dei;
03769    dr.pfds[0] = dr.pfds[1] = -1;
03770    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03771    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03772    if (rooteid)
03773       dr.root_eid = *rooteid;
03774    /* Create transactions */
03775    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03776 
03777    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03778       do this earlier because we didn't know if we were going to have transactions
03779       or not. */
03780    if (!ttl) {
03781       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03782       return 0;
03783    }
03784 
03785    /* Optimize transactions */
03786    optimize_transactions(&dr, 9999);
03787    /* Actually perform transactions */
03788    query_transactions(&dr);
03789    /* Wait for transaction to come back */
03790    start = ast_tvnow();
03791    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03792       usleep(1);
03793    res = dr.respcount;
03794    return res;
03795 }

static int dundi_query_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 3904 of file pbx_dundi.c.

References ARRAY_LEN, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_datastore::data, drds_destroy(), dundi_lookup(), dundi_query_opts, dundi_result_datastore::id, LOG_ERROR, LOG_WARNING, dundi_result_datastore::num_results, OPT_BYPASS_CACHE, parse(), dundi_result_datastore::results, and sort_results().

03905 {
03906    struct ast_module_user *u;
03907    AST_DECLARE_APP_ARGS(args,
03908       AST_APP_ARG(number);
03909       AST_APP_ARG(context);
03910       AST_APP_ARG(options);
03911    );
03912    struct ast_flags opts = { 0, };
03913    char *parse;
03914    struct dundi_result_datastore *drds;
03915    struct ast_datastore *datastore;
03916 
03917    u = ast_module_user_add(chan);
03918 
03919    if (ast_strlen_zero(data)) {
03920       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
03921       ast_module_user_remove(u);
03922       return -1;
03923    }
03924 
03925    if (!chan) {
03926       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
03927       ast_module_user_remove(u);
03928       return -1;
03929    }
03930 
03931    parse = ast_strdupa(data);
03932 
03933    AST_STANDARD_APP_ARGS(args, parse);
03934 
03935    if (!ast_strlen_zero(args.options))
03936       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03937 
03938    if (ast_strlen_zero(args.context))
03939       args.context = "e164";
03940 
03941    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
03942       ast_module_user_remove(u);
03943       return -1;
03944    }
03945 
03946    drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
03947    snprintf(buf, len, "%u", drds->id);
03948 
03949    if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) {
03950       drds_destroy(drds);
03951       ast_module_user_remove(u);
03952       return -1;
03953    }
03954 
03955    datastore->data = drds;
03956 
03957    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context,
03958       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
03959 
03960    if (drds->num_results > 0)
03961       sort_results(drds->results, drds->num_results);
03962 
03963    ast_channel_lock(chan);
03964    ast_channel_datastore_add(chan, datastore);
03965    ast_channel_unlock(chan);
03966 
03967    ast_module_user_remove(u);
03968 
03969    return 0;
03970 }

static void* dundi_query_thread ( void *  data  )  [static]

Definition at line 655 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, dundi_entity_info::country, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, dundi_entity_info::email, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, dundi_query_state::reqeid, dundi_entity_info::stateprov, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

00656 {
00657    struct dundi_query_state *st = data;
00658    struct dundi_entity_info dei;
00659    struct dundi_ie_data ied;
00660    struct dundi_hint_metadata hmd;
00661    char eid_str[20];
00662    int res;
00663 
00664    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00665       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00666    memset(&ied, 0, sizeof(ied));
00667    memset(&dei, 0, sizeof(dei));
00668    memset(&hmd, 0, sizeof(hmd));
00669    if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00670       /* Ooh, it's us! */
00671       ast_debug(1, "Neat, someone look for us!\n");
00672       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00673       ast_copy_string(dei.org, org, sizeof(dei.org));
00674       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00675       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00676       ast_copy_string(dei.country, country, sizeof(dei.country));
00677       ast_copy_string(dei.email, email, sizeof(dei.email));
00678       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00679       res = 1;
00680    } else {
00681       /* If we do not have a canonical result, keep looking */
00682       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00683    }
00684    AST_LIST_LOCK(&peers);
00685    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00686       ast_debug(1, "Our transaction went away!\n");
00687       st->trans->thread = 0;
00688       destroy_trans(st->trans, 0);
00689    } else {
00690       if (res) {
00691          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00692          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00693          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00694          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00695          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00696          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00697          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00698          if (!ast_strlen_zero(dei.ipaddr))
00699             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00700       }
00701       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00702       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00703       st->trans->thread = 0;
00704    }
00705    AST_LIST_UNLOCK(&peers);
00706    ast_free(st);
00707    return NULL;
00708 }

static void dundi_reject ( struct dundi_hdr h,
struct sockaddr_in *  sin 
) [static]

Definition at line 367 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_hdr::cmdresp, dundi_hdr::dtrans, DUNDI_COMMAND_INVALID, dundi_xmit(), dundi_hdr::iseqno, dundi_hdr::oseqno, and dundi_hdr::strans.

Referenced by handle_frame().

00368 {
00369    struct {
00370       struct dundi_packet pack;
00371       struct dundi_hdr hdr;
00372    } tmp;
00373    struct dundi_transaction trans;
00374    /* Never respond to an INVALID with another INVALID */
00375    if (h->cmdresp == DUNDI_COMMAND_INVALID)
00376       return;
00377    memset(&tmp, 0, sizeof(tmp));
00378    memset(&trans, 0, sizeof(trans));
00379    memcpy(&trans.addr, sin, sizeof(trans.addr));
00380    tmp.hdr.strans = h->dtrans;
00381    tmp.hdr.dtrans = h->strans;
00382    tmp.hdr.iseqno = h->oseqno;
00383    tmp.hdr.oseqno = h->iseqno;
00384    tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00385    tmp.hdr.cmdflags = 0;
00386    tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00387    tmp.pack.datalen = sizeof(struct dundi_hdr);
00388    tmp.pack.parent = &trans;
00389    dundi_xmit(&tmp.pack);
00390 }

static int dundi_result_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 3984 of file pbx_dundi.c.

References AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_datastore::data, dundi_result::dest, LOG_ERROR, LOG_WARNING, num, dundi_result_datastore::num_results, parse(), dundi_result_datastore::results, and dundi_result::tech.

03985 {
03986    struct ast_module_user *u;
03987    AST_DECLARE_APP_ARGS(args,
03988       AST_APP_ARG(id);
03989       AST_APP_ARG(resultnum);
03990    );
03991    char *parse;
03992    unsigned int num;
03993    struct dundi_result_datastore *drds;
03994    struct ast_datastore *datastore;
03995    int res = -1;
03996 
03997    u = ast_module_user_add(chan);
03998 
03999    if (ast_strlen_zero(data)) {
04000       ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n");
04001       goto finish;
04002    }
04003 
04004    if (!chan) {
04005       ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n");
04006       goto finish;
04007    }
04008 
04009    parse = ast_strdupa(data);
04010 
04011    AST_STANDARD_APP_ARGS(args, parse);
04012 
04013    if (ast_strlen_zero(args.id)) {
04014       ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n");
04015       goto finish;
04016    }
04017 
04018    if (ast_strlen_zero(args.resultnum)) {
04019       ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n");
04020       goto finish;
04021    }
04022 
04023    ast_channel_lock(chan);
04024    datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id);
04025    ast_channel_unlock(chan);
04026 
04027    if (!datastore) {
04028       ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id);
04029       goto finish;
04030    }
04031 
04032    drds = datastore->data;
04033 
04034    if (!strcasecmp(args.resultnum, "getnum")) {
04035       snprintf(buf, len, "%u", drds->num_results);
04036       res = 0;
04037       goto finish;
04038    }
04039 
04040    if (sscanf(args.resultnum, "%30u", &num) != 1) {
04041       ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n",
04042          args.resultnum);
04043       goto finish;
04044    }
04045 
04046    if (num && num <= drds->num_results) {
04047       snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest);
04048       res = 0;
04049    } else
04050       ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id);
04051 
04052 finish:
04053    ast_module_user_remove(u);
04054 
04055    return res;
04056 }

static int dundi_rexmit ( const void *  data  )  [static]

Definition at line 2963 of file pbx_dundi.c.

References dundi_transaction::addr, ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, destroy_trans(), dundi_xmit(), FLAG_ISQUAL, dundi_packet::h, LOG_NOTICE, dundi_hdr::oseqno, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, and dundi_hdr::strans.

Referenced by dundi_send().

02964 {
02965    struct dundi_packet *pack = (struct dundi_packet *)data;
02966    int res;
02967    AST_LIST_LOCK(&peers);
02968    if (pack->retrans < 1) {
02969       pack->retransid = -1;
02970       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
02971          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",
02972             ast_inet_ntoa(pack->parent->addr.sin_addr),
02973             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
02974       destroy_trans(pack->parent, 1);
02975       res = 0;
02976    } else {
02977       /* Decrement retransmission, try again */
02978       pack->retrans--;
02979       dundi_xmit(pack);
02980       res = 1;
02981    }
02982    AST_LIST_UNLOCK(&peers);
02983    return res;
02984 }

static int dundi_send ( struct dundi_transaction trans,
int  cmdresp,
int  flags,
int  final,
struct dundi_ie_data ied 
) [static]

Definition at line 2986 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, ast_eid_to_str(), ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_sched_add(), ast_set_flag, ast_test_flag, dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_ACK, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_FINAL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_DEFAULT_RETRANS, dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, dundi_packet::h, dundi_hdr::ies, dundi_transaction::iseqno, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::packets, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, dundi_transaction::retranstimer, dundi_transaction::strans, dundi_hdr::strans, and dundi_transaction::them_eid.

Referenced by cancel_request(), do_register(), dundi_ack(), dundi_answer_entity(), dundi_answer_query(), dundi_discover(), dundi_lookup_thread(), dundi_precache_thread(), dundi_prop_precache(), dundi_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().

02987 {
02988    struct dundi_packet *pack;
02989    int res;
02990    int len;
02991    char eid_str[20];
02992    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
02993    /* Reserve enough space for encryption */
02994    if (ast_test_flag(trans, FLAG_ENCRYPT))
02995       len += 384;
02996    pack = ast_calloc(1, len);
02997    if (pack) {
02998       pack->h = (struct dundi_hdr *)(pack->data);
02999       if (cmdresp != DUNDI_COMMAND_ACK) {
03000          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
03001          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
03002          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
03003       }
03004       pack->parent = trans;
03005       pack->h->strans = htons(trans->strans);
03006       pack->h->dtrans = htons(trans->dtrans);
03007       pack->h->iseqno = trans->iseqno;
03008       pack->h->oseqno = trans->oseqno;
03009       pack->h->cmdresp = cmdresp;
03010       pack->datalen = sizeof(struct dundi_hdr);
03011       if (ied) {
03012          memcpy(pack->h->ies, ied->buf, ied->pos);
03013          pack->datalen += ied->pos;
03014       }
03015       if (final) {
03016          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
03017          ast_set_flag(trans, FLAG_FINAL);
03018       }
03019       pack->h->cmdflags = flags;
03020       if (cmdresp != DUNDI_COMMAND_ACK) {
03021          trans->oseqno++;
03022          trans->oseqno = trans->oseqno % 256;
03023       }
03024       trans->aseqno = trans->iseqno;
03025       /* If we have their public key, encrypt */
03026       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
03027          switch(cmdresp) {
03028          case DUNDI_COMMAND_REGREQ:
03029          case DUNDI_COMMAND_REGRESPONSE:
03030          case DUNDI_COMMAND_DPDISCOVER:
03031          case DUNDI_COMMAND_DPRESPONSE:
03032          case DUNDI_COMMAND_EIDQUERY:
03033          case DUNDI_COMMAND_EIDRESPONSE:
03034          case DUNDI_COMMAND_PRECACHERQ:
03035          case DUNDI_COMMAND_PRECACHERP:
03036             if (dundidebug)
03037                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
03038             res = dundi_encrypt(trans, pack);
03039             break;
03040          default:
03041             res = 0;
03042          }
03043       } else
03044          res = 0;
03045       if (!res)
03046          res = dundi_xmit(pack);
03047       if (res)
03048          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03049 
03050       if (cmdresp == DUNDI_COMMAND_ACK)
03051          ast_free(pack);
03052       return res;
03053    }
03054    return -1;
03055 }

static char* dundi_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2195 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02196 {
02197    switch (cmd) {
02198    case CLI_INIT:
02199       e->command = "dundi set debug {on|off}";
02200       e->usage =
02201          "Usage: dundi set debug {on|off}\n"
02202          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02203       return NULL;
02204    case CLI_GENERATE:
02205       return NULL;
02206    }
02207 
02208    if (a->argc != e->args)
02209       return CLI_SHOWUSAGE;
02210 
02211    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02212       dundidebug = 1;
02213       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02214    } else {
02215       dundidebug = 0;
02216       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02217    }
02218    return CLI_SUCCESS;
02219 }

static char* dundi_show_entityid ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2684 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02685 {
02686    char eid_str[20];
02687    switch (cmd) {
02688    case CLI_INIT:
02689       e->command = "dundi show entityid";
02690       e->usage =
02691          "Usage: dundi show entityid\n"
02692          "       Displays the global entityid for this host.\n";
02693       return NULL;
02694    case CLI_GENERATE:
02695       return NULL;
02696    }
02697    if (a->argc != 3)
02698       return CLI_SHOWUSAGE;
02699    AST_LIST_LOCK(&peers);
02700    ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02701    AST_LIST_UNLOCK(&peers);
02702    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02703    return CLI_SUCCESS;
02704 }

static char* dundi_show_mappings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2738 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_mapping::dcontext, dundi_mapping::dest, dundi_flags2str(), ast_cli_args::fd, FORMAT, FORMAT2, get_mapping_weight(), dundi_mapping::lcontext, map, dundi_mapping::options, dundi_mapping::tech, tech2str(), and ast_cli_entry::usage.

02739 {
02740 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02741 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02742    struct dundi_mapping *map;
02743    char fs[256];
02744    char weight[8];
02745    switch (cmd) {
02746    case CLI_INIT:
02747       e->command = "dundi show mappings";
02748       e->usage =
02749          "Usage: dundi show mappings\n"
02750          "       Lists all known DUNDi mappings.\n";
02751       return NULL;
02752    case CLI_GENERATE:
02753       return NULL;
02754    }
02755    if (a->argc != 3)
02756       return CLI_SHOWUSAGE;
02757    AST_LIST_LOCK(&peers);
02758    ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02759    AST_LIST_TRAVERSE(&mappings, map, list) {
02760       snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map));
02761       ast_cli(a->fd, FORMAT, map->dcontext, weight,
02762          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext,
02763          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02764    }
02765    AST_LIST_UNLOCK(&peers);
02766    return CLI_SUCCESS;
02767 #undef FORMAT
02768 #undef FORMAT2
02769 }

static char* dundi_show_peer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2487 of file pbx_dundi.c.

References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_peer_helper(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, dundi_peer::include, dundi_peer::inkey, ast_cli_args::line, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::model, model2str(), ast_cli_args::n, permission::name, dundi_peer::order, dundi_peer::outkey, dundi_peer::permit, ast_cli_args::pos, dundi_peer::registerid, ast_cli_entry::usage, and ast_cli_args::word.

02488 {
02489    struct dundi_peer *peer;
02490    struct permission *p;
02491    char *order;
02492    char eid_str[20];
02493    int x, cnt;
02494    switch (cmd) {
02495    case CLI_INIT:
02496       e->command = "dundi show peer";
02497       e->usage =
02498          "Usage: dundi show peer [peer]\n"
02499          "       Provide a detailed description of a specifid DUNDi peer.\n";
02500       return NULL;
02501    case CLI_GENERATE:
02502       return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
02503    }
02504    if (a->argc != 4)
02505       return CLI_SHOWUSAGE;
02506    AST_LIST_LOCK(&peers);
02507    AST_LIST_TRAVERSE(&peers, peer, list) {
02508       if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
02509          break;
02510    }
02511    if (peer) {
02512       switch(peer->order) {
02513       case 0:
02514          order = "Primary";
02515          break;
02516       case 1:
02517          order = "Secondary";
02518          break;
02519       case 2:
02520          order = "Tertiary";
02521          break;
02522       case 3:
02523          order = "Quartiary";
02524          break;
02525       default:
02526          order = "Unknown";
02527       }
02528       ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02529       ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));
02530       ast_cli(a->fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02531       ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02532       ast_cli(a->fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02533       ast_cli(a->fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02534       ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02535       if (!AST_LIST_EMPTY(&peer->include))
02536          ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02537       AST_LIST_TRAVERSE(&peer->include, p, list)
02538          ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02539       if (!AST_LIST_EMPTY(&peer->permit))
02540          ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02541       AST_LIST_TRAVERSE(&peer->permit, p, list)
02542          ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02543       cnt = 0;
02544       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02545          if (peer->lookups[x]) {
02546             if (!cnt)
02547                ast_cli(a->fd, "Last few query times:\n");
02548             ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02549             cnt++;
02550          }
02551       }
02552       if (cnt)
02553          ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms);
02554    } else
02555       ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]);
02556    AST_LIST_UNLOCK(&peers);
02557    return CLI_SUCCESS;
02558 }

static char* dundi_show_peers ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2560 of file pbx_dundi.c.

References dundi_peer::addr, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, FORMAT, FORMAT2, dundi_peer::lastms, dundi_peer::maxms, dundi_peer::model, model2str(), status, and ast_cli_entry::usage.

02561 {
02562 #define FORMAT2 "%-20.20s %-15.15s     %-10.10s %-8.8s %-15.15s\n"
02563 #define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
02564    struct dundi_peer *peer;
02565    int registeredonly=0;
02566    char avgms[20];
02567    char eid_str[20];
02568    int online_peers = 0;
02569    int offline_peers = 0;
02570    int unmonitored_peers = 0;
02571    int total_peers = 0;
02572    switch (cmd) {
02573    case CLI_INIT:
02574       e->command = "dundi show peers [registered|include|exclude|begin]";
02575       e->usage =
02576          "Usage: dundi show peers [registered|include|exclude|begin]\n"
02577          "       Lists all known DUNDi peers.\n"
02578          "       If 'registered' is present, only registered peers are shown.\n";
02579       return NULL;
02580    case CLI_GENERATE:
02581       return NULL;
02582    }
02583 
02584    if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5))
02585       return CLI_SHOWUSAGE;
02586    if ((a->argc == 4)) {
02587       if (!strcasecmp(a->argv[3], "registered")) {
02588          registeredonly = 1;
02589       } else
02590          return CLI_SHOWUSAGE;
02591    }
02592    AST_LIST_LOCK(&peers);
02593    ast_cli(a->fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status");
02594    AST_LIST_TRAVERSE(&peers, peer, list) {
02595       char status[20];
02596       int print_line = -1;
02597       char srch[2000];
02598       total_peers++;
02599       if (registeredonly && !peer->addr.sin_addr.s_addr)
02600          continue;
02601       if (peer->maxms) {
02602          if (peer->lastms < 0) {
02603             strcpy(status, "UNREACHABLE");
02604             offline_peers++;
02605          }
02606          else if (peer->lastms > peer->maxms) {
02607             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02608             offline_peers++;
02609          }
02610          else if (peer->lastms) {
02611             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02612             online_peers++;
02613          }
02614          else {
02615             strcpy(status, "UNKNOWN");
02616             offline_peers++;
02617          }
02618       } else {
02619          strcpy(status, "Unmonitored");
02620          unmonitored_peers++;
02621       }
02622       if (peer->avgms)
02623          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02624       else
02625          strcpy(avgms, "Unavail");
02626       snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
02627                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02628                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02629 
02630                 if (a->argc == 5) {
02631                   if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {
02632                         print_line = -1;
02633                    } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) {
02634                         print_line = 1;
02635                    } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) {
02636                         print_line = -1;
02637                    } else {
02638                         print_line = 0;
02639                   }
02640                 }
02641 
02642         if (print_line) {
02643          ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
02644                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02645                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02646       }
02647    }
02648    ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02649    AST_LIST_UNLOCK(&peers);
02650    return CLI_SUCCESS;
02651 #undef FORMAT
02652 #undef FORMAT2
02653 }

static char* dundi_show_precache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2771 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache_queue::context, dundi_precache_queue::expiration, ast_cli_args::fd, FORMAT, FORMAT2, dundi_precache_queue::number, s, and ast_cli_entry::usage.

02772 {
02773 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02774 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02775    struct dundi_precache_queue *qe;
02776    int h,m,s;
02777    time_t now;
02778    switch (cmd) {
02779    case CLI_INIT:
02780       e->command = "dundi show precache";
02781       e->usage =
02782          "Usage: dundi show precache\n"
02783          "       Lists all known DUNDi scheduled precache updates.\n";
02784       return NULL;
02785    case CLI_GENERATE:
02786       return NULL;
02787    }
02788    if (a->argc != 3)
02789       return CLI_SHOWUSAGE;
02790    time(&now);
02791    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
02792    AST_LIST_LOCK(&pcq);
02793    AST_LIST_TRAVERSE(&pcq, qe, list) {
02794       s = qe->expiration - now;
02795       h = s / 3600;
02796       s = s % 3600;
02797       m = s / 60;
02798       s = s % 60;
02799       ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
02800    }
02801    AST_LIST_UNLOCK(&pcq);
02802 
02803    return CLI_SUCCESS;
02804 #undef FORMAT
02805 #undef FORMAT2
02806 }

static char* dundi_show_requests ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2706 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_request::dcontext, dundi_eid_zero(), ast_cli_args::fd, FORMAT, FORMAT2, dundi_request::maxcount, dundi_request::number, dundi_request::respcount, dundi_request::root_eid, and ast_cli_entry::usage.

02707 {
02708 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02709 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02710    struct dundi_request *req;
02711    char eidstr[20];
02712    switch (cmd) {
02713    case CLI_INIT:
02714       e->command = "dundi show requests";
02715       e->usage =
02716          "Usage: dundi show requests\n"
02717          "       Lists all known pending DUNDi requests.\n";
02718       return NULL;
02719    case CLI_GENERATE:
02720       return NULL;
02721    }
02722    if (a->argc != 3)
02723       return CLI_SHOWUSAGE;
02724    AST_LIST_LOCK(&peers);
02725    ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02726    AST_LIST_TRAVERSE(&requests, req, list) {
02727       ast_cli(a->fd, FORMAT, req->number, req->dcontext,
02728          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02729    }
02730    AST_LIST_UNLOCK(&peers);
02731    return CLI_SUCCESS;
02732 #undef FORMAT
02733 #undef FORMAT2
02734 }

static char* dundi_show_trans ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2655 of file pbx_dundi.c.

References dundi_transaction::addr, ast_cli_args::argc, dundi_transaction::aseqno, ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_transaction::dtrans, ast_cli_args::fd, FORMAT, FORMAT2, dundi_transaction::iseqno, dundi_transaction::oseqno, dundi_transaction::strans, and ast_cli_entry::usage.

02656 {
02657 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02658 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02659    struct dundi_transaction *trans;
02660    switch (cmd) {
02661    case CLI_INIT:
02662       e->command = "dundi show trans";
02663       e->usage =
02664          "Usage: dundi show trans\n"
02665          "       Lists all known DUNDi transactions.\n";
02666       return NULL;
02667    case CLI_GENERATE:
02668       return NULL;
02669    }
02670    if (a->argc != 3)
02671       return CLI_SHOWUSAGE;
02672    AST_LIST_LOCK(&peers);
02673    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02674    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02675       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),
02676          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02677    }
02678    AST_LIST_UNLOCK(&peers);
02679    return CLI_SUCCESS;
02680 #undef FORMAT
02681 #undef FORMAT2
02682 }

static char* dundi_store_history ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2221 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02222 {
02223    switch (cmd) {
02224    case CLI_INIT:
02225       e->command = "dundi store history {on|off}";
02226       e->usage =
02227          "Usage: dundi store history {on|off}\n"
02228          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02229          "purposes\n";
02230       return NULL;
02231    case CLI_GENERATE:
02232       return NULL;
02233    }
02234 
02235    if (a->argc != e->args)
02236       return CLI_SHOWUSAGE;
02237 
02238    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02239       global_storehistory = 1;
02240       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02241    } else {
02242       global_storehistory = 0;
02243       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02244    }
02245    return CLI_SUCCESS;
02246 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

Definition at line 2855 of file pbx_dundi.c.

References dundi_transaction::addr, ast_inet_ntoa(), ast_log(), dundi_packet::data, dundi_packet::datalen, dundi_showframe(), errno, dundi_packet::h, LOG_WARNING, and dundi_packet::parent.

Referenced by dundi_reject(), dundi_rexmit(), and dundi_send().

02856 {
02857    int res;
02858    if (dundidebug)
02859       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02860    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02861    if (res < 0) {
02862       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",
02863          ast_inet_ntoa(pack->parent->addr.sin_addr),
02864          ntohs(pack->parent->addr.sin_port), strerror(errno));
02865    }
02866    if (res > 0)
02867       res = 0;
02868    return res;
02869 }

static int dundifunc_read ( struct ast_channel chan,
const char *  cmd,
char *  num,
char *  buf,
size_t  len 
) [static]

Definition at line 3813 of file pbx_dundi.c.

References AST_APP_ARG, ast_app_parse_options(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, DUNDI_FLAG_EXISTS, dundi_lookup(), dundi_query_opts, LOG_WARNING, OPT_BYPASS_CACHE, parse(), and sort_results().

03814 {
03815    int results;
03816    int x;
03817    struct ast_module_user *u;
03818    struct dundi_result dr[MAX_RESULTS];
03819    AST_DECLARE_APP_ARGS(args,
03820       AST_APP_ARG(number);
03821       AST_APP_ARG(context);
03822       AST_APP_ARG(options);
03823    );
03824    char *parse;
03825    struct ast_flags opts = { 0, };
03826 
03827    buf[0] = '\0';
03828 
03829    if (ast_strlen_zero(num)) {
03830       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03831       return -1;
03832    }
03833 
03834    u = ast_module_user_add(chan);
03835 
03836    parse = ast_strdupa(num);
03837 
03838    AST_STANDARD_APP_ARGS(args, parse);
03839 
03840    if (!ast_strlen_zero(args.options)) {
03841       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03842    }
03843    if (ast_strlen_zero(args.context)) {
03844       args.context = "e164";
03845    }
03846 
03847    results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
03848    if (results > 0) {
03849       sort_results(dr, results);
03850       for (x = 0; x < results; x++) {
03851          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03852             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03853             break;
03854          }
03855       }
03856    }
03857 
03858    ast_module_user_remove(u);
03859 
03860    return 0;
03861 }

static int encrypt_memcpy ( unsigned char *  dst,
unsigned char *  src,
int  len,
unsigned char *  iv,
ast_aes_encrypt_key ecx 
) [static]

Definition at line 1270 of file pbx_dundi.c.

References ast_aes_encrypt.

Referenced by dundi_encrypt().

01271 {
01272    unsigned char curblock[16];
01273    int x;
01274    memcpy(curblock, iv, sizeof(curblock));
01275    while(len > 0) {
01276       for (x=0;x<16;x++)
01277          curblock[x] ^= src[x];
01278       ast_aes_encrypt(curblock, dst, ecx);
01279       memcpy(curblock, dst, sizeof(curblock));
01280       dst += 16;
01281       src += 16;
01282       len -= 16;
01283    }
01284    return 0;
01285 }

static struct dundi_peer* find_peer ( dundi_eid eid  )  [static, read]

Definition at line 427 of file pbx_dundi.c.

References any_peer, ast_eid_cmp(), AST_LIST_TRAVERSE, and dundi_peer::eid.

00428 {
00429    struct dundi_peer *cur = NULL;
00430 
00431    if (!eid)
00432       eid = &empty_eid;
00433 
00434    AST_LIST_TRAVERSE(&peers, cur, list) {
00435       if (!ast_eid_cmp(&cur->eid,eid))
00436          break;
00437    }
00438 
00439    if (!cur && any_peer)
00440       cur = any_peer;
00441 
00442    return cur;
00443 }

static struct dundi_transaction* find_transaction ( struct dundi_hdr hdr,
struct sockaddr_in *  sin 
) [static, read]

Definition at line 325 of file pbx_dundi.c.

References dundi_transaction::addr, AST_LIST_TRAVERSE, dundi_hdr::cmdresp, create_transaction(), dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_ENCRYPT, DUNDI_COMMAND_NULL, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, inaddrcmp(), dundi_hdr::strans, and dundi_transaction::strans.

Referenced by acf_transaction_read(), acf_transaction_write(), ast_odbc_release_obj(), commit_exec(), handle_frame(), and rollback_exec().

00326 {
00327    struct dundi_transaction *trans;
00328 
00329    /* Look for an exact match first */
00330    AST_LIST_TRAVERSE(&alltrans, trans, all) {
00331       if (!inaddrcmp(&trans->addr, sin) &&
00332            ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
00333            ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
00334            if (hdr->strans)
00335               trans->dtrans = ntohs(hdr->strans) & 32767;
00336            return trans;
00337       }
00338    }
00339 
00340    switch(hdr->cmdresp & 0x7f) {
00341    case DUNDI_COMMAND_DPDISCOVER:
00342    case DUNDI_COMMAND_EIDQUERY:
00343    case DUNDI_COMMAND_PRECACHERQ:
00344    case DUNDI_COMMAND_REGREQ:
00345    case DUNDI_COMMAND_NULL:
00346    case DUNDI_COMMAND_ENCRYPT:
00347       if (!hdr->strans)
00348          break;
00349       /* Create new transaction */
00350       if (!(trans = create_transaction(NULL)))
00351          break;
00352       memcpy(&trans->addr, sin, sizeof(trans->addr));
00353       trans->dtrans = ntohs(hdr->strans) & 32767;
00354    default:
00355       break;
00356    }
00357 
00358    return trans;
00359 }

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 471 of file pbx_dundi.c.

References dundi_mapping::_weight, buf, MAX_WEIGHT, pbx_substitute_variables_helper(), and dundi_mapping::weightstr.

Referenced by dundi_lookup_local(), and dundi_show_mappings().

00472 {
00473    char buf[32];
00474 
00475    buf[0] = 0;
00476    if (map->weightstr) {
00477       pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
00478       if (sscanf(buf, "%30d", &map->_weight) != 1)
00479          map->_weight = MAX_WEIGHT;
00480    }
00481 
00482    return map->_weight;
00483 }

static int get_trans_id ( void   )  [static]

Definition at line 392 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_random(), and dundi_transaction::strans.

Referenced by create_transaction(), and reset_transaction().

00393 {
00394    struct dundi_transaction *t;
00395    int stid = (ast_random() % 32766) + 1;
00396    int tid = stid;
00397 
00398    do {
00399       AST_LIST_TRAVERSE(&alltrans, t, all) {
00400          if (t->strans == tid)
00401             break;
00402       }
00403       if (!t)
00404          return tid;
00405       tid = (tid % 32766) + 1;
00406    } while (tid != stid);
00407 
00408    return 0;
00409 }

static int handle_command_response ( struct dundi_transaction trans,
struct dundi_hdr hdr,
int  datalen,
int  encrypted 
) [static]

Definition at line 1477 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, apply_peer(), dundi_transaction::aseqno, ast_calloc, ast_clear_flag, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_set_flag, ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verb, cache_save(), cache_save_hint(), dundi_ies::called_context, dundi_ies::called_number, dundi_ies::cause, check_key(), dundi_hdr::cmdresp, dundi_entity_info::country, dundi_hint::data, dundi_answer::data, dundi_request::dcontext, dundi_transaction::dcx, deep_copy_peer(), dundi_request::dei, dundi_result::dest, do_register_expire(), dundi_request::dr, dundi_ack(), dundi_answer_entity(), dundi_answer_query(), DUNDI_CAUSE_GENERAL, DUNDI_CAUSE_NOAUTH, DUNDI_COMMAND_CANCEL, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_ENCREJ, DUNDI_COMMAND_ENCRYPT, DUNDI_COMMAND_INVALID, DUNDI_COMMAND_NULL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_COMMAND_UNKNOWN, dundi_decrypt(), dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_byte(), dundi_ie_append_cause(), dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_raw(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_EXPIRATION, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, DUNDI_IE_UNKNOWN, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_showframe(), dundi_peer::dynamic, dundi_transaction::ecx, dundi_answer::eid, dundi_result::eid, dundi_peer::eid, dundi_result::eid_str, dundi_ies::eidcount, dundi_ies::eids, dundi_entity_info::email, dundi_ies::encblock, dundi_encblock::encdata, dundi_ies::enclen, dundi_ies::encsharedkey, dundi_ies::encsig, dundi_request::expiration, dundi_result::expiration, dundi_ies::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, FLAG_SENDFULLKEY, dundi_answer::flags, dundi_result::flags, has_permission(), dundi_ies::hint, dundi_request::hmd, dundi_hdr::ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, dundi_entity_info::ipaddr, dundi_transaction::iseqno, dundi_encblock::iv, dundi_ies::keycrc32, dundi_transaction::lasttrans, dundi_entity_info::locality, LOG_NOTICE, LOG_WARNING, MAX_PACKET_SIZE, dundi_request::maxcount, dundi_peer::model, dundi_request::number, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_entity_info::phone, dundi_ie_data::pos, dundi_answer::protocol, dundi_ies::q_country, dundi_ies::q_dept, dundi_ies::q_email, dundi_ies::q_ipaddr, dundi_ies::q_locality, dundi_ies::q_org, dundi_ies::q_phone, dundi_ies::q_stateprov, qualify_peer(), dundi_request::query_eid, dundi_peer::registerexpire, reset_transaction(), dundi_request::respcount, dundi_peer::sentfullkey, dundi_entity_info::stateprov, dundi_result::tech, tech2str(), dundi_result::techint, dundi_peer::them_dcx, dundi_peer::them_ecx, dundi_transaction::them_eid, dundi_peer::txenckey, dundi_peer::us_eid, dundi_transaction::us_eid, dundi_answer::weight, and dundi_result::weight.

Referenced by handle_frame().

01478 {
01479    /* Handle canonical command / response */
01480    int final = hdr->cmdresp & 0x80;
01481    int cmd = hdr->cmdresp & 0x7f;
01482    int x,y,z;
01483    int resp;
01484    int res;
01485    int authpass=0;
01486    unsigned char *bufcpy;
01487 #ifdef LOW_MEMORY
01488    struct dundi_ie_data *ied = ast_calloc(1, sizeof(*ied));
01489 #else
01490    struct dundi_ie_data _ied = {
01491       .pos = 0,
01492    };
01493    struct dundi_ie_data *ied = &_ied;
01494 #endif
01495    struct dundi_ies ies = {
01496       .eidcount = 0,
01497    };
01498    struct dundi_peer *peer = NULL;
01499    char eid_str[20];
01500    char eid_str2[20];
01501    int retval = -1;
01502 
01503    if (!ied) {
01504       return -1;
01505    }
01506 
01507    if (datalen) {
01508       bufcpy = alloca(datalen);
01509       if (!bufcpy) {
01510          goto return_cleanup;
01511       }
01512       /* Make a copy for parsing */
01513       memcpy(bufcpy, hdr->ies, datalen);
01514       ast_debug(1, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : "");
01515       if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) {
01516          ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n");
01517          goto return_cleanup;
01518       }
01519    }
01520    switch(cmd) {
01521    case DUNDI_COMMAND_DPDISCOVER:
01522    case DUNDI_COMMAND_EIDQUERY:
01523    case DUNDI_COMMAND_PRECACHERQ:
01524       if (cmd == DUNDI_COMMAND_EIDQUERY)
01525          resp = DUNDI_COMMAND_EIDRESPONSE;
01526       else if (cmd == DUNDI_COMMAND_PRECACHERQ)
01527          resp = DUNDI_COMMAND_PRECACHERP;
01528       else
01529          resp = DUNDI_COMMAND_DPRESPONSE;
01530       /* A dialplan or entity discover -- qualify by highest level entity */
01531       peer = find_peer(ies.eids[0]);
01532       if (!peer) {
01533          dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
01534          dundi_send(trans, resp, 0, 1, ied);
01535       } else {
01536          int hasauth = 0;
01537          trans->us_eid = peer->us_eid;
01538          if (strlen(peer->inkey)) {
01539             hasauth = encrypted;
01540          } else
01541             hasauth = 1;
01542          if (hasauth) {
01543             /* Okay we're authentiated and all, now we check if they're authorized */
01544             if (!ies.called_context)
01545                ies.called_context = "e164";
01546             if (cmd == DUNDI_COMMAND_EIDQUERY) {
01547                res = dundi_answer_entity(trans, &ies, ies.called_context);
01548             } else {
01549                if (ast_strlen_zero(ies.called_number)) {
01550                   /* They're not permitted to access that context */
01551                   dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity");
01552                   dundi_send(trans, resp, 0, 1, ied);
01553                } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) &&
01554                           (peer->model & DUNDI_MODEL_INBOUND) &&
01555                         has_permission(&peer->permit, ies.called_context)) {
01556                   res = dundi_answer_query(trans, &ies, ies.called_context);
01557                   if (res < 0) {
01558                      /* There is no such dundi context */
01559                      dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
01560                      dundi_send(trans, resp, 0, 1, ied);
01561                   }
01562                } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) &&
01563                           (peer->pcmodel & DUNDI_MODEL_INBOUND) &&
01564                         has_permission(&peer->include, ies.called_context)) {
01565                   res = dundi_prop_precache(trans, &ies, ies.called_context);
01566                   if (res < 0) {
01567                      /* There is no such dundi context */
01568                      dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
01569                      dundi_send(trans, resp, 0, 1, ied);
01570                   }
01571                } else {
01572                   /* They're not permitted to access that context */
01573                   dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied");
01574                   dundi_send(trans, resp, 0, 1, ied);
01575                }
01576             }
01577          } else {
01578             /* They're not permitted to access that context */
01579             dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted");
01580             dundi_send(trans, resp, 0, 1, ied);
01581          }
01582       }
01583       break;
01584    case DUNDI_COMMAND_REGREQ:
01585       /* A register request -- should only have one entity */
01586       peer = find_peer(ies.eids[0]);
01587 
01588       /* if the peer is not found and we have a valid 'any_peer' setting */
01589       if (any_peer && peer == any_peer) {
01590          /* copy any_peer into a new peer object */
01591          peer = ast_calloc(1, sizeof(*peer));
01592          if (peer) {
01593             deep_copy_peer(peer, any_peer);
01594 
01595             /* set EID to remote EID */
01596             peer->eid = *ies.eids[0];
01597 
01598             AST_LIST_LOCK(&peers);
01599             AST_LIST_INSERT_HEAD(&peers, peer, list);
01600             AST_LIST_UNLOCK(&peers);
01601          }
01602       }
01603 
01604       if (!peer || !peer->dynamic) {
01605          dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
01606          dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied);
01607       } else {
01608          int hasauth = 0;
01609          trans->us_eid = peer->us_eid;
01610          if (!ast_strlen_zero(peer->inkey)) {
01611             hasauth = encrypted;
01612          } else
01613             hasauth = 1;
01614          if (hasauth) {
01615             int expire = default_expiration;
01616             char data[256];
01617             int needqual = 0;
01618             AST_SCHED_DEL(sched, peer->registerexpire);
01619             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
01620             snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr),
01621                ntohs(trans->addr.sin_port), expire);
01622             ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data);
01623             if (inaddrcmp(&peer->addr, &trans->addr)) {
01624                ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n",
01625                      ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
01626                      ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port));
01627                needqual = 1;
01628             }
01629 
01630             memcpy(&peer->addr, &trans->addr, sizeof(peer->addr));
01631             dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration);
01632             dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied);
01633             if (needqual)
01634                qualify_peer(peer, 1);
01635          }
01636       }
01637       break;
01638    case DUNDI_COMMAND_DPRESPONSE:
01639       /* A dialplan response, lets see what we got... */
01640       if (ies.cause < 1) {
01641          /* Success of some sort */
01642          ast_debug(1, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount);
01643          if (ast_test_flag(trans, FLAG_ENCRYPT)) {
01644             authpass = encrypted;
01645          } else
01646             authpass = 1;
01647          if (authpass) {
01648             /* Pass back up answers */
01649             if (trans->parent && trans->parent->dr) {
01650                y = trans->parent->respcount;
01651                for (x=0;x<ies.anscount;x++) {
01652                   if (trans->parent->respcount < trans->parent->maxcount) {
01653                      /* Make sure it's not already there */
01654                      for (z=0;z<trans->parent->respcount;z++) {
01655                         if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) &&
01656                             !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data))
01657                               break;
01658                      }
01659                      if (z == trans->parent->respcount) {
01660                         /* Copy into parent responses */
01661                         trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags);
01662                         trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol;
01663                         trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight);
01664                         trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid;
01665                         if (ies.expiration > 0)
01666                            trans->parent->dr[trans->parent->respcount].expiration = ies.expiration;
01667                         else
01668                            trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
01669                         ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
01670                            sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
01671                            &ies.answers[x]->eid);
01672                         ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data,
01673                            sizeof(trans->parent->dr[trans->parent->respcount].dest));
01674                         ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol),
01675                            sizeof(trans->parent->dr[trans->parent->respcount].tech));
01676                         trans->parent->respcount++;
01677                         ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
01678                      } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) {
01679                         /* Update weight if appropriate */
01680                         trans->parent->dr[z].weight = ies.answers[x]->weight;
01681                      }
01682                   } else
01683                      ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n",
01684                         trans->parent->number, trans->parent->dcontext);
01685                }
01686                /* Save all the results (if any) we had.  Even if no results, still cache lookup.  Let
01687                   the cache know if this request was unaffected by our entity list. */
01688                cache_save(&trans->them_eid, trans->parent, y,
01689                      ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0);
01690                if (ies.hint) {
01691                   cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration);
01692                   if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
01693                      ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
01694                   if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) {
01695                      if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) {
01696                         ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data,
01697                            sizeof(trans->parent->hmd->exten));
01698                      }
01699                   } else {
01700                      ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
01701                   }
01702                }
01703                if (ies.expiration > 0) {
01704                   if (trans->parent->expiration > ies.expiration) {
01705                      trans->parent->expiration = ies.expiration;
01706                   }
01707                }
01708             }
01709             /* Close connection if not final */
01710             if (!final)
01711                dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01712          }
01713 
01714       } else {
01715          /* Auth failure, check for data */
01716          if (!final) {
01717             /* Cancel if they didn't already */
01718             dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01719          }
01720       }
01721       break;
01722    case DUNDI_COMMAND_EIDRESPONSE:
01723       /* A dialplan response, lets see what we got... */
01724       if (ies.cause < 1) {
01725          /* Success of some sort */
01726          ast_debug(1, "Looks like success of some sort (%d)\n", ies.cause);
01727          if (ast_test_flag(trans, FLAG_ENCRYPT)) {
01728             authpass = encrypted;
01729          } else
01730             authpass = 1;
01731          if (authpass) {
01732             /* Pass back up answers */
01733             if (trans->parent && trans->parent->dei && ies.q_org) {
01734                if (!trans->parent->respcount) {
01735                   trans->parent->respcount++;
01736                   if (ies.q_dept)
01737                      ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit));
01738                   if (ies.q_org)
01739                      ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org));
01740                   if (ies.q_locality)
01741                      ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality));
01742                   if (ies.q_stateprov)
01743                      ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov));
01744                   if (ies.q_country)
01745                      ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country));
01746                   if (ies.q_email)
01747                      ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email));
01748                   if (ies.q_phone)
01749                      ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone));
01750                   if (ies.q_ipaddr)
01751                      ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr));
01752                   if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) {
01753                      /* If it's them, update our address */
01754                      ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr));
01755                   }
01756                }
01757                if (ies.hint) {
01758                   if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
01759                      ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
01760                }
01761             }
01762             /* Close connection if not final */
01763             if (!final)
01764                dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01765          }
01766 
01767       } else {
01768          /* Auth failure, check for data */
01769          if (!final) {
01770             /* Cancel if they didn't already */
01771             dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01772          }
01773       }
01774       break;
01775    case DUNDI_COMMAND_REGRESPONSE:
01776       /* A dialplan response, lets see what we got... */
01777       if (ies.cause < 1) {
01778          int hasauth;
01779          /* Success of some sort */
01780          if (ast_test_flag(trans, FLAG_ENCRYPT)) {
01781             hasauth = encrypted;
01782          } else
01783             hasauth = 1;
01784 
01785          if (!hasauth) {
01786             ast_log(LOG_NOTICE, "Reponse to register not authorized!\n");
01787             if (!final) {
01788                dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer");
01789                dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, ied);
01790             }
01791          } else {
01792             ast_debug(1, "Yay, we've registered as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid),
01793                   ast_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid));
01794             /* Close connection if not final */
01795             if (!final)
01796                dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01797          }
01798       } else {
01799          /* Auth failure, cancel if they didn't for some reason */
01800          if (!final) {
01801             dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01802          }
01803       }
01804       break;
01805    case DUNDI_COMMAND_INVALID:
01806    case DUNDI_COMMAND_NULL:
01807    case DUNDI_COMMAND_PRECACHERP:
01808       /* Do nothing special */
01809       if (!final)
01810          dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01811       break;
01812    case DUNDI_COMMAND_ENCREJ:
01813       if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || AST_LIST_EMPTY(&trans->lasttrans) || !(peer = find_peer(&trans->them_eid))) {
01814          /* No really, it's over at this point */
01815          if (!final)
01816             dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
01817       } else {
01818          /* Send with full key */
01819          ast_set_flag(trans, FLAG_SENDFULLKEY);
01820          if (final) {
01821             /* Ooops, we got a final message, start by sending ACK... */
01822             dundi_ack(trans, hdr->cmdresp & 0x80);
01823             trans->aseqno = trans->iseqno;
01824             /* Now, we gotta create a new transaction */
01825             if (!reset_transaction(trans)) {
01826                /* Make sure handle_frame doesn't destroy us */
01827                hdr->cmdresp &= 0x7f;
01828                /* Parse the message we transmitted */
01829                memset(&ies, 0, sizeof(ies));
01830                dundi_parse_ies(&ies, (AST_LIST_FIRST(&trans->lasttrans))->h->ies, (AST_LIST_FIRST(&trans->lasttrans))->datalen - sizeof(struct dundi_hdr));
01831                /* Reconstruct outgoing encrypted packet */
01832                memset(ied, 0, sizeof(*ied));
01833                dundi_ie_append_eid(ied, DUNDI_IE_EID, &trans->us_eid);
01834                dundi_ie_append_raw(ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
01835                dundi_ie_append_raw(ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
01836                if (ies.encblock)
01837                   dundi_ie_append_encdata(ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen);
01838                dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, (AST_LIST_FIRST(&trans->lasttrans))->h->cmdresp & 0x80, ied);
01839                peer->sentfullkey = 1;
01840             }
01841          }
01842       }
01843       break;
01844    case DUNDI_COMMAND_ENCRYPT:
01845       if (!encrypted) {
01846          /* No nested encryption! */
01847          if ((trans->iseqno == 1) && !trans->oseqno) {
01848             if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) ||
01849                ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) ||
01850                (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) {
01851                if (!final) {
01852                   dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
01853                }
01854                break;
01855             }
01856             apply_peer(trans, peer);
01857             /* Key passed, use new contexts for this session */
01858             trans->ecx = peer->them_ecx;
01859             trans->dcx = peer->them_dcx;
01860          }
01861          if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) {
01862             struct dundi_hdr *dhdr;
01863             unsigned char decoded[MAX_PACKET_SIZE];
01864             int ddatalen;
01865             ddatalen = sizeof(decoded);
01866             dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen);
01867             if (dhdr) {
01868                /* Handle decrypted response */
01869                if (dundidebug)
01870                   dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr));
01871                handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1);
01872                /* Carry back final flag */
01873                hdr->cmdresp |= dhdr->cmdresp & 0x80;
01874                break;
01875             } else {
01876                ast_debug(1, "Ouch, decrypt failed :(\n");
01877             }
01878          }
01879       }
01880       if (!final) {
01881          /* Turn off encryption */
01882          ast_clear_flag(trans, FLAG_ENCRYPT);
01883          dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
01884       }
01885       break;
01886    default:
01887       /* Send unknown command if we don't know it, with final flag IFF it's the
01888          first command in the dialog and only if we haven't received final notification */
01889       if (!final) {
01890          dundi_ie_append_byte(ied, DUNDI_IE_UNKNOWN, cmd);
01891          dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, ied);
01892       }
01893    }
01894 
01895    retval = 0;
01896 
01897 return_cleanup:
01898 #ifdef LOW_MEMORY
01899    ast_free(ied);
01900 #endif
01901    return retval;
01902 }

static int handle_frame ( struct dundi_hdr h,
struct sockaddr_in *  sin,
int  datalen 
) [static]

Definition at line 1937 of file pbx_dundi.c.

References ack_trans(), dundi_transaction::aseqno, ast_debug, ast_test_flag, dundi_hdr::cmdresp, destroy_packets(), destroy_trans(), dundi_ack(), DUNDI_COMMAND_ACK, dundi_reject(), find_transaction(), FLAG_FINAL, handle_command_response(), dundi_hdr::iseqno, dundi_transaction::iseqno, dundi_transaction::lasttrans, dundi_transaction::oiseqno, and dundi_hdr::oseqno.

01938 {
01939    struct dundi_transaction *trans;
01940    trans = find_transaction(h, sin);
01941    if (!trans) {
01942       dundi_reject(h, sin);
01943       return 0;
01944    }
01945    /* Got a transaction, see where this header fits in */
01946    if (h->oseqno == trans->iseqno) {
01947       /* Just what we were looking for...  Anything but ack increments iseqno */
01948       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
01949          /* If final, we're done */
01950          destroy_trans(trans, 0);
01951          return 0;
01952       }
01953       if (h->cmdresp != DUNDI_COMMAND_ACK) {
01954          trans->oiseqno = trans->iseqno;
01955          trans->iseqno++;
01956          handle_command_response(trans, h, datalen, 0);
01957       }
01958       if (trans->aseqno != trans->iseqno) {
01959          dundi_ack(trans, h->cmdresp & 0x80);
01960          trans->aseqno = trans->iseqno;
01961       }
01962       /* Delete any saved last transmissions */
01963       destroy_packets(&trans->lasttrans);
01964       if (h->cmdresp & 0x80) {
01965          /* Final -- destroy now */
01966          destroy_trans(trans, 0);
01967       }
01968    } else if (h->oseqno == trans->oiseqno) {
01969       /* Last incoming sequence number -- send ACK without processing */
01970       dundi_ack(trans, 0);
01971    } else {
01972       /* Out of window -- simply drop */
01973       ast_debug(1, "Dropping packet out of window!\n");
01974    }
01975    return 0;
01976 }

static int has_permission ( struct permissionlist *  permlist,
char *  cont 
) [static]

Definition at line 281 of file pbx_dundi.c.

References permission::allow, AST_LIST_TRAVERSE, and permission::name.

Referenced by build_transactions(), dundi_ie_append_eid_appropriately(), handle_command_response(), and optimize_transactions().

00282 {
00283    struct permission *perm;
00284    int res = 0;
00285 
00286    AST_LIST_TRAVERSE(permlist, perm, list) {
00287       if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
00288          res = perm->allow;
00289    }
00290 
00291    return res;
00292 }

static int load_module ( void   )  [static]

Definition at line 4770 of file pbx_dundi.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_netsock_set_qos(), ast_register_switch(), ast_verb, dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, sched_context_create(), set_config(), and start_network_thread().

04771 {
04772    struct sockaddr_in sin;
04773 
04774    dundi_set_output(dundi_debug_output);
04775    dundi_set_error(dundi_error_output);
04776 
04777    sin.sin_family = AF_INET;
04778    sin.sin_port = ntohs(DUNDI_PORT);
04779    sin.sin_addr.s_addr = INADDR_ANY;
04780 
04781    /* Make a UDP socket */
04782    io = io_context_create();
04783    sched = sched_context_create();
04784 
04785    if (!io || !sched)
04786       return AST_MODULE_LOAD_FAILURE;
04787 
04788    if (set_config("dundi.conf", &sin, 0))
04789       return AST_MODULE_LOAD_DECLINE;
04790 
04791    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04792 
04793    if (netsocket < 0) {
04794       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04795       return AST_MODULE_LOAD_FAILURE;
04796    }
04797    if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {
04798       ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n",
04799          ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
04800       return AST_MODULE_LOAD_FAILURE;
04801    }
04802 
04803    ast_netsock_set_qos(netsocket, tos, 0, "DUNDi");
04804 
04805    if (start_network_thread()) {
04806       ast_log(LOG_ERROR, "Unable to start network thread\n");
04807       close(netsocket);
04808       return AST_MODULE_LOAD_FAILURE;
04809    }
04810 
04811    ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi));
04812    if (ast_register_switch(&dundi_switch))
04813       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04814    ast_custom_function_register(&dundi_function);
04815    ast_custom_function_register(&dundi_query_function);
04816    ast_custom_function_register(&dundi_result_function);
04817 
04818    ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04819 
04820    return AST_MODULE_LOAD_SUCCESS;
04821 }

static void load_password ( void   )  [static]

Definition at line 2034 of file pbx_dundi.c.

References ast_copy_string(), ast_db_get(), ast_get_time_t(), build_secret(), DUNDI_SECRET_TIME, last, and save_secret().

Referenced by set_config().

02035 {
02036    char *current=NULL;
02037    char *last=NULL;
02038    char tmp[256];
02039    time_t expired;
02040 
02041    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02042    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02043       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02044       current = strchr(tmp, ';');
02045       if (!current)
02046          current = tmp;
02047       else {
02048          *current = '\0';
02049          current++;
02050       };
02051       if ((time(NULL) - expired) < 0) {
02052          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02053             expired = time(NULL) + DUNDI_SECRET_TIME;
02054       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02055          last = current;
02056          current = NULL;
02057       } else {
02058          last = NULL;
02059          current = NULL;
02060       }
02061    }
02062    if (current) {
02063       /* Current key is still valid, just setup rotatation properly */
02064       ast_copy_string(cursecret, current, sizeof(cursecret));
02065       rotatetime = expired;
02066    } else {
02067       /* Current key is out of date, rotate or eliminate all together */
02068       build_secret(cursecret, sizeof(cursecret));
02069       save_secret(cursecret, last);
02070    }
02071 }

static void mark_mappings ( void   )  [static]

Definition at line 4081 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_mapping::dead, and map.

Referenced by set_config(), and unload_module().

04082 {
04083    struct dundi_mapping *map;
04084 
04085    AST_LIST_LOCK(&peers);
04086    AST_LIST_TRAVERSE(&mappings, map, list) {
04087       map->dead = 1;
04088    }
04089    AST_LIST_UNLOCK(&peers);
04090 }

static void mark_peers ( void   )  [static]

Definition at line 4071 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and dundi_peer::dead.

Referenced by set_config(), and unload_module().

04072 {
04073    struct dundi_peer *peer;
04074    AST_LIST_LOCK(&peers);
04075    AST_LIST_TRAVERSE(&peers, peer, list) {
04076       peer->dead = 1;
04077    }
04078    AST_LIST_UNLOCK(&peers);
04079 }

static char* model2str ( int  model  )  [static]

Definition at line 2293 of file pbx_dundi.c.

References DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, and DUNDI_MODEL_SYMMETRIC.

Referenced by dundi_show_peer(), and dundi_show_peers().

02294 {
02295    switch(model) {
02296    case DUNDI_MODEL_INBOUND:
02297       return "Inbound";
02298    case DUNDI_MODEL_OUTBOUND:
02299       return "Outbound";
02300    case DUNDI_MODEL_SYMMETRIC:
02301       return "Symmetric";
02302    default:
02303       return "Unknown";
02304    }
02305 }

static void* network_thread ( void *  ignore  )  [static]

Definition at line 2090 of file pbx_dundi.c.

References ast_io_add(), AST_IO_IN, ast_io_wait(), AST_LIST_LOCK, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_sched_runq(), ast_sched_wait(), check_password(), and socket_read().

02091 {
02092    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames
02093       from the network, and queue them for delivery to the channels */
02094    int res;
02095    /* Establish I/O callback for socket read */
02096    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02097 
02098    while (!dundi_shutdown) {
02099       res = ast_sched_wait(sched);
02100       if ((res > 1000) || (res < 0))
02101          res = 1000;
02102       res = ast_io_wait(io, res);
02103       if (res >= 0) {
02104          AST_LIST_LOCK(&peers);
02105          ast_sched_runq(sched);
02106          AST_LIST_UNLOCK(&peers);
02107       }
02108       check_password();
02109    }
02110 
02111    netthreadid = AST_PTHREADT_NULL;
02112 
02113    return NULL;
02114 }

static int optimize_transactions ( struct dundi_request dr,
int  order 
) [static]

Definition at line 3261 of file pbx_dundi.c.

References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), dundi_peer::include, dundi_peer::order, dundi_transaction::them_eid, dundi_request::trans, and dundi_transaction::us_eid.

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

03262 {
03263    /* Minimize the message propagation through DUNDi by
03264       alerting the network to hops which should be not be considered */
03265    struct dundi_transaction *trans;
03266    struct dundi_peer *peer;
03267    dundi_eid tmp;
03268    int x;
03269    int needpush;
03270 
03271    AST_LIST_LOCK(&peers);
03272    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03273       /* Pop off the true root */
03274       if (trans->eidcount) {
03275          tmp = trans->eids[--trans->eidcount];
03276          needpush = 1;
03277       } else {
03278          tmp = trans->us_eid;
03279          needpush = 0;
03280       }
03281 
03282       AST_LIST_TRAVERSE(&peers, peer, list) {
03283          if (has_permission(&peer->include, dr->dcontext) &&
03284              ast_eid_cmp(&peer->eid, &trans->them_eid) &&
03285             (peer->order <= order)) {
03286             /* For each other transaction, make sure we don't
03287                ask this EID about the others if they're not
03288                already in the list */
03289             if (!ast_eid_cmp(&tmp, &peer->eid))
03290                x = -1;
03291             else {
03292                for (x=0;x<trans->eidcount;x++) {
03293                   if (!ast_eid_cmp(&trans->eids[x], &peer->eid))
03294                      break;
03295                }
03296             }
03297             if (x == trans->eidcount) {
03298                /* Nope not in the list, if needed, add us at the end since we're the source */
03299                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03300                   trans->eids[trans->eidcount++] = peer->eid;
03301                   /* Need to insert the real root (or us) at the bottom now as
03302                      a requirement now.  */
03303                   needpush = 1;
03304                }
03305             }
03306          }
03307       }
03308       /* If necessary, push the true root back on the end */
03309       if (needpush)
03310          trans->eids[trans->eidcount++] = tmp;
03311    }
03312    AST_LIST_UNLOCK(&peers);
03313 
03314    return 0;
03315 }

static void populate_addr ( struct dundi_peer peer,
dundi_eid eid 
) [static]

Definition at line 4294 of file pbx_dundi.c.

References dundi_peer::addr, ast_db_get(), ast_eid_to_str(), ast_sched_add(), do_register_expire(), inet_aton(), and dundi_peer::registerexpire.

Referenced by build_peer().

04295 {
04296    char data[256];
04297    char *c;
04298    int port, expire;
04299    char eid_str[20];
04300    ast_eid_to_str(eid_str, sizeof(eid_str), eid);
04301    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04302       c = strchr(data, ':');
04303       if (c) {
04304          *c = '\0';
04305          c++;
04306          if (sscanf(c, "%5d:%30d", &port, &expire) == 2) {
04307             /* Got it! */
04308             inet_aton(data, &peer->addr.sin_addr);
04309             peer->addr.sin_family = AF_INET;
04310             peer->addr.sin_port = htons(port);
04311             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04312          }
04313       }
04314    }
04315 }

static int precache_trans ( struct dundi_transaction trans,
struct dundi_mapping maps,
int  mapcount,
int *  minexp,
int *  foundanswers 
) [static]

Definition at line 3114 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, destroy_trans(), do_autokill(), DUNDI_COMMAND_PRECACHERQ, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_eid(), dundi_ie_append_hint(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, dundi_result::expiration, dundi_hint_metadata::exten, dundi_hint_metadata::flags, LOG_WARNING, dundi_request::number, dundi_transaction::parent, dundi_transaction::them_eid, dundi_transaction::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by precache_transactions().

03115 {
03116    struct dundi_ie_data ied;
03117    int x, res;
03118    int max = 999999;
03119    int expiration = dundi_cache_time;
03120    int ouranswers=0;
03121    dundi_eid *avoid[1] = { NULL, };
03122    int direct[1] = { 0, };
03123    struct dundi_result dr[MAX_RESULTS];
03124    struct dundi_hint_metadata hmd;
03125    if (!trans->parent) {
03126       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03127       return -1;
03128    }
03129    memset(&hmd, 0, sizeof(hmd));
03130    memset(&dr, 0, sizeof(dr));
03131    /* Look up the answers we're going to include */
03132    for (x=0;x<mapcount;x++)
03133       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03134    if (ouranswers < 0)
03135       ouranswers = 0;
03136    for (x=0;x<ouranswers;x++) {
03137       if (dr[x].weight < max)
03138          max = dr[x].weight;
03139    }
03140    if (max) {
03141       /* If we do not have a canonical result, keep looking */
03142       res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, trans->parent->dcontext, trans->parent->number, trans->ttl, 1, &hmd, &expiration, 0, 1, &trans->them_eid, avoid, direct);
03143       if (res > 0) {
03144          /* Append answer in result */
03145          ouranswers += res;
03146       }
03147    }
03148 
03149    if (ouranswers > 0) {
03150       *foundanswers += ouranswers;
03151       memset(&ied, 0, sizeof(ied));
03152       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03153       if (!dundi_eid_zero(&trans->us_eid))
03154          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03155       for (x=0;x<trans->eidcount;x++)
03156          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03157       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03158       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03159       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03160       for (x=0;x<ouranswers;x++) {
03161          /* Add answers */
03162          if (dr[x].expiration && (expiration > dr[x].expiration))
03163             expiration = dr[x].expiration;
03164          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03165       }
03166       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03167       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03168       if (trans->autokilltimeout)
03169          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03170       if (expiration < *minexp)
03171          *minexp = expiration;
03172       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03173    } else {
03174       /* Oops, nothing to send... */
03175       destroy_trans(trans, 0);
03176       return 0;
03177    }
03178 }

static int precache_transactions ( struct dundi_request dr,
struct dundi_mapping maps,
int  mapcount,
int *  expiration,
int *  foundanswers 
) [static]

Definition at line 3213 of file pbx_dundi.c.

References ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_test_flag, destroy_trans(), FLAG_DEAD, LOG_WARNING, precache_trans(), dundi_transaction::thread, and dundi_request::trans.

Referenced by dundi_precache_internal().

03214 {
03215    struct dundi_transaction *trans;
03216 
03217    /* Mark all as "in thread" so they don't disappear */
03218    AST_LIST_LOCK(&peers);
03219    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03220       if (trans->thread)
03221          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03222       trans->thread = 1;
03223    }
03224    AST_LIST_UNLOCK(&peers);
03225 
03226    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03227       if (!ast_test_flag(trans, FLAG_DEAD))
03228          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03229    }
03230 
03231    /* Cleanup any that got destroyed in the mean time */
03232    AST_LIST_LOCK(&peers);
03233    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03234       trans->thread = 0;
03235       if (ast_test_flag(trans, FLAG_DEAD)) {
03236          ast_debug(1, "Our transaction went away!\n");
03237          /* This is going to remove the transaction from the dundi_request's list, as well
03238           * as the global transactions list */
03239          destroy_trans(trans, 0);
03240       }
03241    }
03242    AST_LIST_TRAVERSE_SAFE_END
03243    AST_LIST_UNLOCK(&peers);
03244 
03245    return 0;
03246 }

static void* process_clearcache ( void *  ignore  )  [static]

Definition at line 2116 of file pbx_dundi.c.

References ast_db_del(), ast_db_freetree(), ast_db_gettree(), ast_debug, ast_get_time_t(), AST_PTHREADT_NULL, ast_db_entry::data, ast_db_entry::key, and ast_db_entry::next.

Referenced by start_network_thread().

02117 {
02118    struct ast_db_entry *db_entry, *db_tree;
02119    int striplen = sizeof("/dundi/cache");
02120    time_t now;
02121 
02122    while (!dundi_shutdown) {
02123       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
02124 
02125       time(&now);
02126 
02127       db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
02128       for (; db_entry; db_entry = db_entry->next) {
02129          time_t expiry;
02130 
02131          if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
02132             if (expiry < now) {
02133                ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
02134                ast_db_del("dundi/cache", db_entry->key + striplen);
02135             }
02136          }
02137       }
02138       ast_db_freetree(db_tree);
02139 
02140       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
02141       pthread_testcancel();
02142       sleep(60);
02143       pthread_testcancel();
02144    }
02145 
02146    clearcachethreadid = AST_PTHREADT_NULL;
02147    return NULL;
02148 }

static void* process_precache ( void *  ign  )  [static]

Definition at line 2150 of file pbx_dundi.c.

References ast_copy_string(), ast_free, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, AST_PTHREADT_NULL, dundi_precache_queue::context, dundi_precache(), dundi_precache_queue::expiration, and dundi_precache_queue::number.

Referenced by start_network_thread().

02151 {
02152    struct dundi_precache_queue *qe;
02153    time_t now;
02154    char context[256];
02155    char number[256];
02156    int run;
02157 
02158    while (!dundi_shutdown) {
02159       time(&now);
02160       run = 0;
02161       AST_LIST_LOCK(&pcq);
02162       if ((qe = AST_LIST_FIRST(&pcq))) {
02163          if (!qe->expiration) {
02164             /* Gone...  Remove... */
02165             AST_LIST_REMOVE_HEAD(&pcq, list);
02166             ast_free(qe);
02167          } else if (qe->expiration < now) {
02168             /* Process this entry */
02169             qe->expiration = 0;
02170             ast_copy_string(context, qe->context, sizeof(context));
02171             ast_copy_string(number, qe->number, sizeof(number));
02172             run = 1;
02173          }
02174       }
02175       AST_LIST_UNLOCK(&pcq);
02176       if (run) {
02177          dundi_precache(context, number);
02178       } else
02179          sleep(1);
02180    }
02181 
02182    precachethreadid = AST_PTHREADT_NULL;
02183 
02184    return NULL;
02185 }

static void prune_mappings ( void   )  [static]

Definition at line 4133 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_mapping::dead, destroy_map(), and map.

Referenced by set_config(), and unload_module().

04134 {
04135    struct dundi_mapping *map;
04136 
04137    AST_LIST_LOCK(&peers);
04138    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
04139       if (map->dead) {
04140          AST_LIST_REMOVE_CURRENT(list);
04141          destroy_map(map);
04142       }
04143    }
04144    AST_LIST_TRAVERSE_SAFE_END;
04145    AST_LIST_UNLOCK(&peers);
04146 }

static void prune_peers ( void   )  [static]

Definition at line 4118 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_peer::dead, and destroy_peer().

04119 {
04120    struct dundi_peer *peer;
04121 
04122    AST_LIST_LOCK(&peers);
04123    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
04124       if (peer->dead) {
04125          AST_LIST_REMOVE_CURRENT(list);
04126          destroy_peer(peer);
04127       }
04128    }
04129    AST_LIST_TRAVERSE_SAFE_END;
04130    AST_LIST_UNLOCK(&peers);
04131 }

static void qualify_peer ( struct dundi_peer peer,
int  schedonly 
) [static]

Definition at line 4271 of file pbx_dundi.c.

References ast_sched_add(), AST_SCHED_DEL, ast_set_flag, ast_tvnow(), create_transaction(), destroy_trans(), do_qualify(), DUNDI_COMMAND_NULL, dundi_send(), FLAG_ISQUAL, dundi_peer::lastms, dundi_peer::maxms, dundi_peer::qualifyid, dundi_peer::qualtrans, and dundi_peer::qualtx.

Referenced by build_peer(), do_qualify(), and handle_command_response().

04272 {
04273    int when;
04274    AST_SCHED_DEL(sched, peer->qualifyid);
04275    if (peer->qualtrans)
04276       destroy_trans(peer->qualtrans, 0);
04277    peer->qualtrans = NULL;
04278    if (peer->maxms > 0) {
04279       when = 60000;
04280       if (peer->lastms < 0)
04281          when = 10000;
04282       if (schedonly)
04283          when = 5000;
04284       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04285       if (!schedonly)
04286          peer->qualtrans = create_transaction(peer);
04287       if (peer->qualtrans) {
04288          peer->qualtx = ast_tvnow();
04289          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04290          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04291       }
04292    }
04293 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3248 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_query(), and dundi_request::trans.

Referenced by dundi_query_eid_internal().

03249 {
03250    struct dundi_transaction *trans;
03251 
03252    AST_LIST_LOCK(&peers);
03253    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03254       dundi_query(trans);
03255    }
03256    AST_LIST_UNLOCK(&peers);
03257 
03258    return 0;
03259 }

static int register_request ( struct dundi_request dr,
struct dundi_request **  pending 
) [static]

Definition at line 3432 of file pbx_dundi.c.

References ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::crc32, dundi_request::dcontext, dundi_request::number, and dundi_request::root_eid.

Referenced by dundi_lookup_internal().

03433 {
03434    struct dundi_request *cur;
03435    int res=0;
03436    char eid_str[20];
03437    AST_LIST_LOCK(&peers);
03438    AST_LIST_TRAVERSE(&requests, cur, list) {
03439       ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03440          dr->dcontext, dr->number);
03441       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03442           !strcasecmp(cur->number, dr->number) &&
03443           (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03444          ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n",
03445             cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03446          *pending = cur;
03447          res = 1;
03448          break;
03449       }
03450    }
03451    if (!res) {
03452       ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n",
03453             dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03454       /* Go ahead and link us in since nobody else is searching for this */
03455       AST_LIST_INSERT_HEAD(&requests, dr, list);
03456       *pending = NULL;
03457    }
03458    AST_LIST_UNLOCK(&peers);
03459    return res;
03460 }

static int reload ( void   )  [static]

Definition at line 4760 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04761 {
04762    struct sockaddr_in sin;
04763 
04764    if (set_config("dundi.conf", &sin, 1))
04765       return AST_MODULE_LOAD_FAILURE;
04766 
04767    return AST_MODULE_LOAD_SUCCESS;
04768 }

static void reschedule_precache ( const char *  number,
const char *  context,
int  expiration 
) [static]

Definition at line 3611 of file pbx_dundi.c.

References ast_calloc, AST_LIST_FIRST, AST_LIST_INSERT_AFTER, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_precache_queue::context, dundi_precache_queue::expiration, len(), and dundi_precache_queue::number.

Referenced by dundi_precache_full(), and dundi_precache_internal().

03612 {
03613    int len;
03614    struct dundi_precache_queue *qe, *prev;
03615 
03616    AST_LIST_LOCK(&pcq);
03617    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03618       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03619          AST_LIST_REMOVE_CURRENT(list);
03620          break;
03621       }
03622    }
03623    AST_LIST_TRAVERSE_SAFE_END;
03624    if (!qe) {
03625       len = sizeof(*qe);
03626       len += strlen(number) + 1;
03627       len += strlen(context) + 1;
03628       if (!(qe = ast_calloc(1, len))) {
03629          AST_LIST_UNLOCK(&pcq);
03630          return;
03631       }
03632       strcpy(qe->number, number);
03633       qe->context = qe->number + strlen(number) + 1;
03634       strcpy(qe->context, context);
03635    }
03636    time(&qe->expiration);
03637    qe->expiration += expiration;
03638    if ((prev = AST_LIST_FIRST(&pcq))) {
03639       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->