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/netsock2.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.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 %-16.16s %6d sec %-18s\n"
#define FORMAT   "%-12.12s %-16.16s %6d sec %-18s %-7d %s/%s (%s)\n"
#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 %-6d %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-16.16s %-10.10s %-18s\n"
#define FORMAT2   "%-12.12s %-16.16s %-10.10s %-18s %-7s %s\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 %-6.6s %-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 crc, 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_cache (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_hints (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, struct varshead *headp)
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, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .nonoptreq = "res_crypto", }
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 ast_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 177 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 160 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 161 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 162 of file pbx_dundi.c.

Referenced by build_peer(), and model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 182 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 165 of file pbx_dundi.c.

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

#define FORMAT   "%-12.12s %-16.16s %6d sec %-18s\n"

#define FORMAT   "%-12.12s %-16.16s %6d sec %-18s %-7d %s/%s (%s)\n"

#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 %-6d %-10.10s %-8.8s %-15.15s\n"

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

#define FORMAT2   "%-12.12s %-16.16s %-10.10s %-18s %-7s %s\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 %-6.6s %-10.10s %-8.8s %-15.15s\n"

#define MAX_OPTS   128

Definition at line 4388 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 156 of file pbx_dundi.c.

Referenced by handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 154 of file pbx_dundi.c.

#define MAX_WEIGHT   59999

Definition at line 158 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 167 of file pbx_dundi.c.

00167      {
00168    FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
00169    FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
00170    FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
00171    FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
00172    FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
00173    FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
00174    FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
00175 };

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 4074 of file pbx_dundi.c.

04074      {
04075    OPT_BYPASS_CACHE = (1 << 0),
04076 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 5060 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 5060 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3632 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().

03633 {
03634    struct dundi_transaction *trans;
03635 
03636    AST_LIST_LOCK(&peers);
03637    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03638       /* This will remove the transaction from the list */
03639       destroy_trans(trans, 0);
03640    }
03641    AST_LIST_UNLOCK(&peers);
03642 }

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

Definition at line 2005 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().

02006 {
02007    struct dundi_packet *pack;
02008 
02009    /* Ack transmitted packet corresponding to iseqno */
02010    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
02011       if ((pack->h->oseqno + 1) % 255 == iseqno) {
02012          destroy_packet(pack, 0);
02013          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
02014             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
02015             destroy_packets(&trans->lasttrans);
02016          }
02017          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
02018          AST_SCHED_DEL(sched, trans->autokillid);
02019          return 1;
02020       }
02021    }
02022 
02023    return 0;
02024 }

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

Definition at line 4375 of file pbx_dundi.c.

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

Referenced by build_peer().

04376 {
04377    struct permission *perm;
04378 
04379    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04380       return;
04381 
04382    strcpy(perm->name, s);
04383    perm->allow = allow;
04384 
04385    AST_LIST_INSERT_TAIL(permlist, perm, list);
04386 }

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

Definition at line 3587 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().

03588 {
03589    struct dundi_transaction *trans;
03590    int x;
03591    char eid_str[20];
03592    char eid_str2[20];
03593 
03594    /* Ignore if not registered */
03595    if (!p->addr.sin_addr.s_addr)
03596       return 0;
03597    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03598       return 0;
03599 
03600    if (ast_strlen_zero(dr->number))
03601       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);
03602    else
03603       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);
03604 
03605    trans = create_transaction(p);
03606    if (!trans)
03607       return -1;
03608    trans->parent = dr;
03609    trans->ttl = ttl;
03610    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03611       trans->eids[x] = *avoid[x];
03612    trans->eidcount = x;
03613    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03614 
03615    return 0;
03616 }

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

Definition at line 1292 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().

01293 {
01294    if (!trans->addr.sin_addr.s_addr)
01295       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01296    trans->us_eid = p->us_eid;
01297    trans->them_eid = p->eid;
01298    /* Enable encryption if appropriate */
01299    if (!ast_strlen_zero(p->inkey))
01300       ast_set_flag(trans, FLAG_ENCRYPT);
01301    if (p->maxms) {
01302       trans->autokilltimeout = p->maxms;
01303       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01304       if (p->lastms > 1) {
01305          trans->retranstimer = p->lastms * 2;
01306          /* Keep it from being silly */
01307          if (trans->retranstimer < 150)
01308             trans->retranstimer = 150;
01309       }
01310       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01311          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01312    } else
01313       trans->autokilltimeout = global_autokilltimeout;
01314 }

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

Definition at line 3753 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03754 {
03755    /* Idea is that we're calculating a checksum which is independent of
03756       the order that the EID's are listed in */
03757    uint32_t acrc32 = 0;
03758    int x;
03759    for (x=0;avoid[x];x++) {
03760       /* Order doesn't matter */
03761       if (avoid[x+1]) {
03762          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03763       }
03764    }
03765    return acrc32;
03766 }

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

Definition at line 531 of file pbx_dundi.c.

References ast_random().

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

00532 {
00533    /* XXX Would be nice to be more random XXX */
00534    unsigned int *fluffy;
00535    int x;
00536    fluffy = (unsigned int *)(iv);
00537    for (x=0;x<4;x++)
00538       fluffy[x] = ast_random();
00539 }

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

Definition at line 4390 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().

04391 {
04392    char *t, *fields[MAX_OPTS];
04393    struct dundi_mapping *map;
04394    int x;
04395    int y;
04396 
04397    t = ast_strdupa(value);
04398 
04399    AST_LIST_TRAVERSE(&mappings, map, list) {
04400       /* Find a double match */
04401       if (!strcasecmp(map->dcontext, name) &&
04402          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) &&
04403            (!value[strlen(map->lcontext)] ||
04404             (value[strlen(map->lcontext)] == ','))))
04405          break;
04406    }
04407    if (!map) {
04408       if (!(map = ast_calloc(1, sizeof(*map))))
04409          return;
04410       AST_LIST_INSERT_HEAD(&mappings, map, list);
04411       map->dead = 1;
04412    }
04413    map->options = 0;
04414    memset(fields, 0, sizeof(fields));
04415    x = 0;
04416    while (t && x < MAX_OPTS) {
04417       fields[x++] = t;
04418       t = strchr(t, ',');
04419       if (t) {
04420          *t = '\0';
04421          t++;
04422       }
04423    } /* Russell was here, arrrr! */
04424    if ((x == 1) && ast_strlen_zero(fields[0])) {
04425       /* Placeholder mapping */
04426       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04427       map->dead = 0;
04428    } else if (x >= 4) {
04429       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04430       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04431       if ((sscanf(fields[1], "%30d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) {
04432          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04433          if ((map->tech = str2tech(fields[2])))
04434             map->dead = 0;
04435       } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') {
04436          map->weightstr = ast_strdup(fields[1]);
04437          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04438          if ((map->tech = str2tech(fields[2])))
04439             map->dead = 0;
04440       } else {
04441          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04442       }
04443       for (y = 4;y < x; y++) {
04444          if (!strcasecmp(fields[y], "nounsolicited"))
04445             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04446          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04447             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04448          else if (!strcasecmp(fields[y], "residential"))
04449             map->options |= DUNDI_FLAG_RESIDENTIAL;
04450          else if (!strcasecmp(fields[y], "commercial"))
04451             map->options |= DUNDI_FLAG_COMMERCIAL;
04452          else if (!strcasecmp(fields[y], "mobile"))
04453             map->options |= DUNDI_FLAG_MOBILE;
04454          else if (!strcasecmp(fields[y], "nopartial"))
04455             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04456          else
04457             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04458       }
04459    } else
04460       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04461 }

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

Definition at line 4545 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.

04546 {
04547    struct dundi_peer *peer;
04548    struct ast_hostent he;
04549    struct hostent *hp;
04550    dundi_eid testeid;
04551    int needregister=0;
04552    char eid_str[20];
04553 
04554    AST_LIST_LOCK(&peers);
04555    AST_LIST_TRAVERSE(&peers, peer, list) {
04556       if (!ast_eid_cmp(&peer->eid, eid)) {
04557          break;
04558       }
04559    }
04560    if (!peer) {
04561       /* Add us into the list */
04562       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04563          AST_LIST_UNLOCK(&peers);
04564          return;
04565       }
04566       peer->registerid = -1;
04567       peer->registerexpire = -1;
04568       peer->qualifyid = -1;
04569       peer->addr.sin_family = AF_INET;
04570       peer->addr.sin_port = htons(DUNDI_PORT);
04571       populate_addr(peer, eid);
04572       AST_LIST_INSERT_HEAD(&peers, peer, list);
04573    }
04574    peer->dead = 0;
04575    peer->eid = *eid;
04576    peer->us_eid = global_eid;
04577    destroy_permissions(&peer->permit);
04578    destroy_permissions(&peer->include);
04579    AST_SCHED_DEL(sched, peer->registerid);
04580    for (; v; v = v->next) {
04581       if (!strcasecmp(v->name, "inkey")) {
04582          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04583       } else if (!strcasecmp(v->name, "outkey")) {
04584          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04585       } else if (!strcasecmp(v->name, "port")) {
04586          peer->addr.sin_port = htons(atoi(v->value));
04587       } else if (!strcasecmp(v->name, "host")) {
04588          if (!strcasecmp(v->value, "dynamic")) {
04589             peer->dynamic = 1;
04590          } else {
04591             hp = ast_gethostbyname(v->value, &he);
04592             if (hp) {
04593                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04594                peer->dynamic = 0;
04595             } else {
04596                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04597                peer->dead = 1;
04598             }
04599          }
04600       } else if (!strcasecmp(v->name, "ustothem")) {
04601          if (!ast_str_to_eid(&testeid, v->value))
04602             peer->us_eid = testeid;
04603          else
04604             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04605       } else if (!strcasecmp(v->name, "include")) {
04606          append_permission(&peer->include, v->value, 1);
04607       } else if (!strcasecmp(v->name, "permit")) {
04608          append_permission(&peer->permit, v->value, 1);
04609       } else if (!strcasecmp(v->name, "noinclude")) {
04610          append_permission(&peer->include, v->value, 0);
04611       } else if (!strcasecmp(v->name, "deny")) {
04612          append_permission(&peer->permit, v->value, 0);
04613       } else if (!strcasecmp(v->name, "register")) {
04614          needregister = ast_true(v->value);
04615       } else if (!strcasecmp(v->name, "order")) {
04616          if (!strcasecmp(v->value, "primary"))
04617             peer->order = 0;
04618          else if (!strcasecmp(v->value, "secondary"))
04619             peer->order = 1;
04620          else if (!strcasecmp(v->value, "tertiary"))
04621             peer->order = 2;
04622          else if (!strcasecmp(v->value, "quartiary"))
04623             peer->order = 3;
04624          else {
04625             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);
04626          }
04627       } else if (!strcasecmp(v->name, "qualify")) {
04628          if (!strcasecmp(v->value, "no")) {
04629             peer->maxms = 0;
04630          } else if (!strcasecmp(v->value, "yes")) {
04631             peer->maxms = DEFAULT_MAXMS;
04632          } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) {
04633             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n",
04634                ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04635             peer->maxms = 0;
04636          }
04637       } else if (!strcasecmp(v->name, "model")) {
04638          if (!strcasecmp(v->value, "inbound"))
04639             peer->model = DUNDI_MODEL_INBOUND;
04640          else if (!strcasecmp(v->value, "outbound"))
04641             peer->model = DUNDI_MODEL_OUTBOUND;
04642          else if (!strcasecmp(v->value, "symmetric"))
04643             peer->model = DUNDI_MODEL_SYMMETRIC;
04644          else if (!strcasecmp(v->value, "none"))
04645             peer->model = 0;
04646          else {
04647             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
04648                v->value, v->lineno);
04649          }
04650       } else if (!strcasecmp(v->name, "precache")) {
04651          if (!strcasecmp(v->value, "inbound"))
04652             peer->pcmodel = DUNDI_MODEL_INBOUND;
04653          else if (!strcasecmp(v->value, "outbound"))
04654             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04655          else if (!strcasecmp(v->value, "symmetric"))
04656             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04657          else if (!strcasecmp(v->value, "none"))
04658             peer->pcmodel = 0;
04659          else {
04660             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
04661                v->value, v->lineno);
04662          }
04663       }
04664    }
04665    (*globalpcmode) |= peer->pcmodel;
04666    if (!peer->model && !peer->pcmodel) {
04667       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n",
04668          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04669       peer->dead = 1;
04670    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04671       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n",
04672          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04673       peer->dead = 1;
04674    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04675       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n",
04676          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04677       peer->dead = 1;
04678    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04679       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n",
04680          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04681    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04682       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",
04683          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04684    } else {
04685       if (needregister) {
04686          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04687       }
04688       if (ast_eid_cmp(&peer->eid, &empty_eid)) {
04689          qualify_peer(peer, 1);
04690       }
04691    }
04692    AST_LIST_UNLOCK(&peers);
04693 }

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

Definition at line 2095 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02096 {
02097    unsigned char tmp[16];
02098    char *s;
02099    build_iv(tmp);
02100    secret[0] = '\0';
02101    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02102    /* Eliminate potential bad characters */
02103    while((s = strchr(secret, ';'))) *s = '+';
02104    while((s = strchr(secret, '/'))) *s = '+';
02105    while((s = strchr(secret, ':'))) *s = '+';
02106    while((s = strchr(secret, '@'))) *s = '+';
02107 }

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 3644 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().

03645 {
03646    struct dundi_peer *p;
03647    int x;
03648    int res;
03649    int pass;
03650    int allowconnect;
03651    char eid_str[20];
03652    AST_LIST_LOCK(&peers);
03653    AST_LIST_TRAVERSE(&peers, p, list) {
03654       if (modeselect == 1) {
03655          /* Send the precache to push upstreams only! */
03656          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03657          allowconnect = 1;
03658       } else {
03659          /* Normal lookup / EID query */
03660          pass = has_permission(&p->include, dr->dcontext);
03661          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03662       }
03663       if (skip) {
03664          if (!ast_eid_cmp(skip, &p->eid))
03665             pass = 0;
03666       }
03667       if (pass) {
03668          if (p->order <= order) {
03669             /* Check order first, then check cache, regardless of
03670                omissions, this gets us more likely to not have an
03671                affected answer. */
03672             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03673                res = 0;
03674                /* Make sure we haven't already seen it and that it won't
03675                   affect our answer */
03676                for (x=0;avoid[x];x++) {
03677                   if (!ast_eid_cmp(avoid[x], &p->eid) || !ast_eid_cmp(avoid[x], &p->us_eid)) {
03678                      /* If not a direct connection, it affects our answer */
03679                      if (directs && !directs[x])
03680                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03681                      break;
03682                   }
03683                }
03684                /* Make sure we can ask */
03685                if (allowconnect) {
03686                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03687                      /* Check for a matching or 0 cache entry */
03688                      append_transaction(dr, p, ttl, avoid);
03689                   } else {
03690                      ast_debug(1, "Avoiding '%s' in transaction\n", ast_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03691                   }
03692                }
03693             }
03694             *foundcache |= res;
03695          } else if (!*skipped || (p->order < *skipped))
03696             *skipped = p->order;
03697       }
03698    }
03699    AST_LIST_UNLOCK(&peers);
03700 }

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

Definition at line 1240 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, dundi_request::root_eid, and tmp().

Referenced by build_transactions().

01241 {
01242    char key[256];
01243    char eid_str[20];
01244    char eidroot_str[20];
01245    time_t now;
01246    int res=0;
01247    int res2=0;
01248    char eid_str_full[20];
01249    char tmp[256]="";
01250    int x;
01251 
01252    time(&now);
01253    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01254    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01255    ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01256    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc);
01257    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01258    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, (unsigned)0);
01259    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01260    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01261    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01262    x = 0;
01263    if (!req->respcount) {
01264       while(!res2) {
01265          /* Look and see if we have a hint that would preclude us from looking at this
01266             peer for this number. */
01267          if (!(tmp[x] = req->number[x]))
01268             break;
01269          x++;
01270          /* Check for hints */
01271          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc);
01272          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01273          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, (unsigned)0);
01274          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01275          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01276          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01277          if (res2) {
01278             if (strlen(tmp) > strlen(req->hmd->exten)) {
01279                /* Update meta data if appropriate */
01280                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01281             }
01282          }
01283       }
01284       res |= res2;
01285    }
01286 
01287    return res;
01288 }

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

Definition at line 1168 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, timeout, dundi_result::weight, and weight.

Referenced by cache_lookup().

01169 {
01170    char data[1024];
01171    char *ptr, *term, *src;
01172    int tech;
01173    struct ast_flags flags;
01174    int weight;
01175    int length;
01176    int z;
01177    char fs[256];
01178 
01179    /* Build request string */
01180    if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
01181       time_t timeout;
01182       ptr = data;
01183       if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
01184          int expiration = timeout - now;
01185          if (expiration > 0) {
01186             ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
01187             ptr += length + 1;
01188             while((sscanf(ptr, "%30d/%30d/%30d/%n", (int *)&(flags.flags), &weight, &tech, &length) == 3)) {
01189                ptr += length;
01190                term = strchr(ptr, '|');
01191                if (term) {
01192                   *term = '\0';
01193                   src = strrchr(ptr, '/');
01194                   if (src) {
01195                      *src = '\0';
01196                      src++;
01197                   } else
01198                      src = "";
01199                   ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n",
01200                      tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
01201                   /* Make sure it's not already there */
01202                   for (z=0;z<req->respcount;z++) {
01203                      if ((req->dr[z].techint == tech) &&
01204                          !strcmp(req->dr[z].dest, ptr))
01205                            break;
01206                   }
01207                   if (z == req->respcount) {
01208                      /* Copy into parent responses */
01209                      ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);
01210                      req->dr[req->respcount].weight = weight;
01211                      req->dr[req->respcount].techint = tech;
01212                      req->dr[req->respcount].expiration = expiration;
01213                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
01214                      ast_eid_to_str(req->dr[req->respcount].eid_str,
01215                         sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
01216                      ast_copy_string(req->dr[req->respcount].dest, ptr,
01217                         sizeof(req->dr[req->respcount].dest));
01218                      ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
01219                         sizeof(req->dr[req->respcount].tech));
01220                      req->respcount++;
01221                      ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK);
01222                   } else if (req->dr[z].weight > weight)
01223                      req->dr[z].weight = weight;
01224                   ptr = term + 1;
01225                }
01226             }
01227             /* We found *something* cached */
01228             if (expiration < *lowexpiration)
01229                *lowexpiration = expiration;
01230             return 1;
01231          } else
01232             ast_db_del("dundi/cache", key);
01233       } else
01234          ast_db_del("dundi/cache", key);
01235    }
01236 
01237    return 0;
01238 }

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

Definition at line 897 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, timeout, and dundi_result::weight.

Referenced by dundi_prop_precache(), and handle_command_response().

00898 {
00899    int x;
00900    char key1[256];
00901    char key2[256];
00902    char data[1024];
00903    char eidpeer_str[20];
00904    char eidroot_str[20];
00905    time_t timeout;
00906 
00907    if (expiration < 1)
00908       expiration = dundi_cache_time;
00909 
00910    /* Keep pushes a little longer, cut pulls a little short */
00911    if (push)
00912       expiration += 10;
00913    else
00914       expiration -= 10;
00915    if (expiration < 1)
00916       expiration = 1;
00917    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00918    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00919    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00920    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00921    /* Build request string */
00922    time(&timeout);
00923    timeout += expiration;
00924    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00925    for (x=start;x<req->respcount;x++) {
00926       /* Skip anything with an illegal pipe in it */
00927       if (strchr(req->dr[x].dest, '|'))
00928          continue;
00929       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%u/%d/%d/%s/%s|",
00930          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest,
00931          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00932    }
00933    ast_db_put("dundi/cache", key1, data);
00934    ast_db_put("dundi/cache", key2, data);
00935    return 0;
00936 }

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

Definition at line 862 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, dundi_request::root_eid, and timeout.

Referenced by dundi_prop_precache(), and handle_command_response().

00863 {
00864    int unaffected;
00865    char key1[256];
00866    char key2[256];
00867    char eidpeer_str[20];
00868    char eidroot_str[20];
00869    char data[80];
00870    time_t timeout;
00871 
00872    if (expiration < 0)
00873       expiration = dundi_cache_time;
00874 
00875    /* Only cache hint if "don't ask" is there... */
00876    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))
00877       return 0;
00878 
00879    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00880 
00881    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00882    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00883    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00884    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00885 
00886    time(&timeout);
00887    timeout += expiration;
00888    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00889 
00890    ast_db_put("dundi/cache", key1, data);
00891    ast_debug(1, "Caching hint at '%s'\n", key1);
00892    ast_db_put("dundi/cache", key2, data);
00893    ast_debug(1, "Caching hint at '%s'\n", key2);
00894    return 0;
00895 }

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3618 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03619 {
03620    struct dundi_transaction *trans;
03621 
03622    AST_LIST_LOCK(&peers);
03623    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03624       /* Orphan transaction from request */
03625       trans->parent = NULL;
03626       /* Send final cancel */
03627       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03628    }
03629    AST_LIST_UNLOCK(&peers);
03630 }

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

Definition at line 1486 of file pbx_dundi.c.

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

01487 {
01488    unsigned char dst[128];
01489    int res;
01490    struct ast_key *key, *skey;
01491    char eid_str[20];
01492    ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32);
01493    if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
01494       /* A match */
01495       return 1;
01496    } else if (!newkey || !newsig)
01497       return 0;
01498    if (!memcmp(peer->rxenckey, newkey, 128) &&
01499        !memcmp(peer->rxenckey + 128, newsig, 128)) {
01500       /* By definition, a match */
01501       return 1;
01502    }
01503    /* Decrypt key */
01504    key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01505    if (!key) {
01506       ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
01507          peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01508       return -1;
01509    }
01510 
01511    skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01512    if (!skey) {
01513       ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
01514          peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01515       return -1;
01516    }
01517 
01518    /* First check signature */
01519    res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
01520    if (res)
01521       return 0;
01522 
01523    res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
01524    if (res != 16) {
01525       if (res >= 0)
01526          ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
01527       return 0;
01528    }
01529    /* Decrypted, passes signature */
01530    ast_debug(1, "Wow, new key combo passed signature and decrypt!\n");
01531    memcpy(peer->rxenckey, newkey, 128);
01532    memcpy(peer->rxenckey + 128, newsig, 128);
01533    peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
01534    ast_aes_set_decrypt_key(dst, &peer->them_dcx);
01535    ast_aes_set_encrypt_key(dst, &peer->them_ecx);
01536    return 1;
01537 }

static void check_password ( void   )  [static]

Definition at line 2162 of file pbx_dundi.c.

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

02163 {
02164    char oldsecret[80];
02165    time_t now;
02166 
02167    time(&now);
02168 #if 0
02169    printf("%ld/%ld\n", now, rotatetime);
02170 #endif
02171    if ((now - rotatetime) >= 0) {
02172       /* Time to rotate keys */
02173       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02174       build_secret(cursecret, sizeof(cursecret));
02175       save_secret(cursecret, oldsecret);
02176    }
02177 }

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3739 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

03740 {
03741    struct dundi_request *cur;
03742 
03743    AST_LIST_LOCK(&peers);
03744    AST_LIST_TRAVERSE(&requests, cur, list) {
03745       if (cur == dr)
03746          break;
03747    }
03748    AST_LIST_UNLOCK(&peers);
03749 
03750    return cur ? 1 : 0;
03751 }

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

Definition at line 2399 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 NULL.

Referenced by dundi_show_peer().

02400 {
02401    int which=0, len;
02402    char *ret = NULL;
02403    struct dundi_peer *p;
02404    char eid_str[20];
02405 
02406    if (pos != rpos)
02407       return NULL;
02408    AST_LIST_LOCK(&peers);
02409    len = strlen(word);
02410    AST_LIST_TRAVERSE(&peers, p, list) {
02411       const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02412       if (!strncasecmp(word, s, len) && ++which > state) {
02413          ret = ast_strdup(s);
02414          break;
02415       }
02416    }
02417    AST_LIST_UNLOCK(&peers);
02418    return ret;
02419 }

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

Definition at line 3092 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(), NULL, dundi_transaction::retranstimer, dundi_peer::sentfullkey, dundi_transaction::start, and dundi_transaction::strans.

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

03093 {
03094    struct dundi_transaction *trans;
03095    int tid;
03096 
03097    /* Don't allow creation of transactions to non-registered peers */
03098    if (p && !p->addr.sin_addr.s_addr)
03099       return NULL;
03100    tid = get_trans_id();
03101    if (tid < 1)
03102       return NULL;
03103    if (!(trans = ast_calloc(1, sizeof(*trans))))
03104       return NULL;
03105 
03106    if (global_storehistory) {
03107       trans->start = ast_tvnow();
03108       ast_set_flag(trans, FLAG_STOREHIST);
03109    }
03110    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
03111    trans->autokillid = -1;
03112    if (p) {
03113       apply_peer(trans, p);
03114       if (!p->sentfullkey)
03115          ast_set_flag(trans, FLAG_SENDFULLKEY);
03116    }
03117    trans->strans = tid;
03118    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
03119 
03120    return trans;
03121 }

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

Definition at line 1383 of file pbx_dundi.c.

References ast_aes_decrypt().

Referenced by dundi_decrypt().

01384 {
01385    unsigned char lastblock[16];
01386    int x;
01387    memcpy(lastblock, iv, sizeof(lastblock));
01388    while(len > 0) {
01389       ast_aes_decrypt(src, dst, dcx);
01390       for (x=0;x<16;x++)
01391          dst[x] ^= lastblock[x];
01392       memcpy(lastblock, src, sizeof(lastblock));
01393       dst += 16;
01394       src += 16;
01395       len -= 16;
01396    }
01397    return 0;
01398 }

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

Definition at line 1539 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().

01540 {
01541    struct permission *cur, *perm;
01542 
01543    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01544 
01545    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01546    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01547 
01548    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01549       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01550          continue;
01551 
01552       perm->allow = cur->allow;
01553       strcpy(perm->name, cur->name);
01554 
01555       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01556    }
01557 
01558    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01559       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01560          continue;
01561 
01562       perm->allow = cur->allow;
01563       strcpy(perm->name, cur->name);
01564 
01565       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01566    }
01567 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4338 of file pbx_dundi.c.

References ast_free, and dundi_mapping::weightstr.

Referenced by prune_mappings().

04339 {
04340    if (map->weightstr)
04341       ast_free(map->weightstr);
04342    ast_free(map);
04343 }

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

Definition at line 3139 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().

03140 {
03141    if (pack->parent)
03142       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
03143    AST_SCHED_DEL(sched, pack->retransid);
03144    if (needfree)
03145       ast_free(pack);
03146 }

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

Definition at line 1994 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().

01995 {
01996    struct dundi_packet *pack;
01997 
01998    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01999       AST_SCHED_DEL(sched, pack->retransid);
02000       ast_free(pack);
02001    }
02002 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

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

Definition at line 4319 of file pbx_dundi.c.

References ast_free, and AST_LIST_REMOVE_HEAD.

Referenced by build_peer(), and destroy_peer().

04320 {
04321    struct permission *perm;
04322 
04323    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04324       ast_free(perm);
04325 }

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

Definition at line 3148 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, NULL, 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().

03149 {
03150    struct dundi_peer *peer;
03151    int ms;
03152    int x;
03153    int cnt;
03154    char eid_str[20];
03155    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
03156       AST_LIST_TRAVERSE(&peers, peer, list) {
03157          if (peer->regtrans == trans)
03158             peer->regtrans = NULL;
03159          if (peer->qualtrans == trans) {
03160             if (fromtimeout) {
03161                if (peer->lastms > -1)
03162                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
03163                peer->lastms = -1;
03164             } else {
03165                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
03166                if (ms < 1)
03167                   ms = 1;
03168                if (ms < peer->maxms) {
03169                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
03170                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
03171                } else if (peer->lastms < peer->maxms) {
03172                   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);
03173                }
03174                peer->lastms = ms;
03175             }
03176             peer->qualtrans = NULL;
03177          }
03178          if (ast_test_flag(trans, FLAG_STOREHIST)) {
03179             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
03180                if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) {
03181                   peer->avgms = 0;
03182                   cnt = 0;
03183                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
03184                      ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
03185                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
03186                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
03187                      peer->lookups[x] = peer->lookups[x-1];
03188                      if (peer->lookups[x]) {
03189                         peer->avgms += peer->lookuptimes[x];
03190                         cnt++;
03191                      }
03192                   }
03193                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
03194                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
03195                   if (peer->lookups[0]) {
03196                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
03197                      peer->avgms += peer->lookuptimes[0];
03198                      cnt++;
03199                   }
03200                   if (cnt)
03201                      peer->avgms /= cnt;
03202                }
03203             }
03204          }
03205       }
03206    }
03207    if (trans->parent) {
03208       /* Unlink from parent if appropriate */
03209       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
03210       if (AST_LIST_EMPTY(&trans->parent->trans)) {
03211          /* Wake up sleeper */
03212          if (trans->parent->pfds[1] > -1) {
03213             if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
03214                ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
03215             }
03216          }
03217       }
03218    }
03219    /* Unlink from all trans */
03220    AST_LIST_REMOVE(&alltrans, trans, all);
03221    destroy_packets(&trans->packets);
03222    destroy_packets(&trans->lasttrans);
03223    AST_SCHED_DEL(sched, trans->autokillid);
03224    if (trans->thread) {
03225       /* If used by a thread, mark as dead and be done */
03226       ast_set_flag(trans, FLAG_DEAD);
03227    } else
03228       ast_free(trans);
03229 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3470 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().

03471 {
03472    struct dundi_transaction *trans;
03473    AST_LIST_LOCK(&peers);
03474    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03475       dundi_discover(trans);
03476    }
03477    AST_LIST_UNLOCK(&peers);
03478    return 0;
03479 }

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

Definition at line 3325 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().

03326 {
03327    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03328    char eid_str[20];
03329    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n",
03330       ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03331    trans->autokillid = -1;
03332    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03333    return 0;
03334 }

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

Definition at line 4490 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04491 {
04492    struct dundi_peer *peer = (struct dundi_peer *)data;
04493    peer->qualifyid = -1;
04494    qualify_peer(peer, 0);
04495    return 0;
04496 }

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

Definition at line 4464 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().

04465 {
04466    struct dundi_ie_data ied;
04467    struct dundi_peer *peer = (struct dundi_peer *)data;
04468    char eid_str[20];
04469    char eid_str2[20];
04470    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));
04471    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04472    /* Destroy old transaction if there is one */
04473    if (peer->regtrans)
04474       destroy_trans(peer->regtrans, 0);
04475    peer->regtrans = create_transaction(peer);
04476    if (peer->regtrans) {
04477       ast_set_flag(peer->regtrans, FLAG_ISREG);
04478       memset(&ied, 0, sizeof(ied));
04479       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04480       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04481       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04482       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04483 
04484    } else
04485       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));
04486 
04487    return 0;
04488 }

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

Note:
Called with the peers list already locked

Definition at line 1317 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().

01318 {
01319    struct dundi_peer *peer = (struct dundi_peer *)data;
01320    char eid_str[20];
01321    ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01322    peer->registerexpire = -1;
01323    peer->lastms = 0;
01324    memset(&peer->addr, 0, sizeof(peer->addr));
01325    return 0;
01326 }

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 4144 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

04145 {
04146    ast_free(drds);
04147 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 4149 of file pbx_dundi.c.

References drds_destroy().

04150 {
04151    struct dundi_result_datastore *drds = data;
04152    drds_destroy(drds);
04153 }

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

Definition at line 449 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, dundi_send(), and NULL.

Referenced by handle_command_response(), and handle_frame().

00450 {
00451    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00452 }

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

Definition at line 807 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, NULL, dundi_ies::reqeid, dundi_query_state::reqeid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

00808 {
00809    struct dundi_query_state *st;
00810    int totallen;
00811    int x;
00812    int skipfirst=0;
00813    char eid_str[20];
00814    char *s;
00815    pthread_t lookupthread;
00816 
00817    if (ies->eidcount > 1) {
00818       /* Since it is a requirement that the first EID is the authenticating host
00819          and the last EID is the root, it is permissible that the first and last EID
00820          could be the same.  In that case, we should go ahead copy only the "root" section
00821          since we will not need it for authentication. */
00822       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00823          skipfirst = 1;
00824    }
00825    totallen = sizeof(struct dundi_query_state);
00826    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00827    st = ast_calloc(1, totallen);
00828    if (st) {
00829       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00830       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00831       st->trans = trans;
00832       st->ttl = ies->ttl - 1;
00833       if (st->ttl < 0)
00834          st->ttl = 0;
00835       s = st->fluffy;
00836       for (x=skipfirst;ies->eids[x];x++) {
00837          st->eids[x-skipfirst] = (dundi_eid *)s;
00838          *st->eids[x-skipfirst] = *ies->eids[x];
00839          s += sizeof(dundi_eid);
00840       }
00841       ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00842 
00843       trans->thread = 1;
00844       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
00845          struct dundi_ie_data ied = { 0, };
00846          trans->thread = 0;
00847          ast_log(LOG_WARNING, "Unable to create thread!\n");
00848          ast_free(st);
00849          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00850          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00851          return -1;
00852       }
00853    } else {
00854       struct dundi_ie_data ied = { 0, };
00855       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00856       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00857       return -1;
00858    }
00859    return 0;
00860 }

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

Definition at line 1085 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, NULL, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

01086 {
01087    struct dundi_query_state *st;
01088    int totallen;
01089    int x;
01090    struct dundi_ie_data ied;
01091    char *s;
01092    struct dundi_mapping *cur;
01093    int mapcount = 0;
01094    int skipfirst = 0;
01095 
01096    pthread_t lookupthread;
01097    totallen = sizeof(struct dundi_query_state);
01098    /* Count matching map entries */
01099    AST_LIST_TRAVERSE(&mappings, cur, list) {
01100       if (!strcasecmp(cur->dcontext, ccontext))
01101          mapcount++;
01102    }
01103    /* If no maps, return -1 immediately */
01104    if (!mapcount)
01105       return -1;
01106 
01107    if (ies->eidcount > 1) {
01108       /* Since it is a requirement that the first EID is the authenticating host
01109          and the last EID is the root, it is permissible that the first and last EID
01110          could be the same.  In that case, we should go ahead copy only the "root" section
01111          since we will not need it for authentication. */
01112       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01113          skipfirst = 1;
01114    }
01115 
01116    totallen += mapcount * sizeof(struct dundi_mapping);
01117    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01118    st = ast_calloc(1, totallen);
01119    if (st) {
01120       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
01121       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01122       st->trans = trans;
01123       st->ttl = ies->ttl - 1;
01124       st->nocache = ies->cbypass;
01125       if (st->ttl < 0)
01126          st->ttl = 0;
01127       s = st->fluffy;
01128       for (x=skipfirst;ies->eids[x];x++) {
01129          st->eids[x-skipfirst] = (dundi_eid *)s;
01130          *st->eids[x-skipfirst] = *ies->eids[x];
01131          st->directs[x-skipfirst] = ies->eid_direct[x];
01132          s += sizeof(dundi_eid);
01133       }
01134       /* Append mappings */
01135       x = 0;
01136       st->maps = (struct dundi_mapping *)s;
01137       AST_LIST_TRAVERSE(&mappings, cur, list) {
01138          if (!strcasecmp(cur->dcontext, ccontext)) {
01139             if (x < mapcount) {
01140                st->maps[x] = *cur;
01141                st->maps[x].list.next = NULL;
01142                x++;
01143             }
01144          }
01145       }
01146       st->nummaps = mapcount;
01147       ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
01148       trans->thread = 1;
01149       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) {
01150          trans->thread = 0;
01151          ast_log(LOG_WARNING, "Unable to create thread!\n");
01152          ast_free(st);
01153          memset(&ied, 0, sizeof(ied));
01154          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01155          dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01156          return -1;
01157       }
01158    } else {
01159       ast_log(LOG_WARNING, "Out of memory!\n");
01160       memset(&ied, 0, sizeof(ied));
01161       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01162       dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01163       return -1;
01164    }
01165    return 0;
01166 }

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04740 {
04741    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04742 }

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

Definition at line 356 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

00357 {
00358    if (dundidebug)
00359       ast_verbose("%s", data);
00360 }

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

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

Referenced by handle_command_response().

01401 {
01402    int space = *dstlen;
01403    unsigned long bytes;
01404    struct dundi_hdr *h;
01405    unsigned char *decrypt_space;
01406    decrypt_space = ast_alloca(srclen);
01407    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01408    /* Setup header */
01409    h = (struct dundi_hdr *)dst;
01410    *h = *ohdr;
01411    bytes = space - 6;
01412    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01413       ast_debug(1, "Ouch, uncompress failed :(\n");
01414       return NULL;
01415    }
01416    /* Update length */
01417    *dstlen = bytes + 6;
01418    /* Return new header */
01419    return h;
01420 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3358 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().

03359 {
03360    struct dundi_ie_data ied;
03361    int x;
03362    if (!trans->parent) {
03363       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03364       return -1;
03365    }
03366    memset(&ied, 0, sizeof(ied));
03367    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03368    if (!dundi_eid_zero(&trans->us_eid))
03369       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03370    for (x=0;x<trans->eidcount;x++)
03371       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03372    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03373    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03374    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03375    if (trans->parent->cbypass)
03376       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03377    if (trans->autokilltimeout)
03378       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03379    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03380 }

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

Definition at line 2438 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, NULL, sort_results(), dundi_result::tech, tmp(), ast_cli_entry::usage, and dundi_result::weight.

02439 {
02440    int res;
02441    char tmp[256];
02442    char fs[80] = "";
02443    char *context;
02444    int x;
02445    int bypass = 0;
02446    struct dundi_result dr[MAX_RESULTS];
02447    struct timeval start;
02448    switch (cmd) {
02449    case CLI_INIT:
02450       e->command = "dundi lookup";
02451       e->usage =
02452          "Usage: dundi lookup <number>[@context] [bypass]\n"
02453          "       Lookup the given number within the given DUNDi context\n"
02454          "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
02455          "keyword is specified.\n";
02456       return NULL;
02457    case CLI_GENERATE:
02458       return NULL;
02459    }
02460 
02461    if ((a->argc < 3) || (a->argc > 4)) {
02462       return CLI_SHOWUSAGE;
02463    }
02464    if (a->argc > 3) {
02465       if (!strcasecmp(a->argv[3], "bypass")) {
02466          bypass=1;
02467       } else {
02468          return CLI_SHOWUSAGE;
02469       }
02470    }
02471    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02472    context = strchr(tmp, '@');
02473    if (context) {
02474       *context = '\0';
02475       context++;
02476    }
02477    start = ast_tvnow();
02478    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02479 
02480    if (res < 0)
02481       ast_cli(a->fd, "DUNDi lookup returned error.\n");
02482    else if (!res)
02483       ast_cli(a->fd, "DUNDi lookup returned no results.\n");
02484    else
02485       sort_results(dr, res);
02486    for (x=0;x<res;x++) {
02487       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));
02488       ast_cli(a->fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02489    }
02490    ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02491    return CLI_SUCCESS;
02492 }

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

Definition at line 2494 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, NULL, tmp(), and ast_cli_entry::usage.

02495 {
02496    int res;
02497    char tmp[256];
02498    char *context;
02499    struct timeval start;
02500    switch (cmd) {
02501    case CLI_INIT:
02502       e->command = "dundi precache";
02503       e->usage =
02504          "Usage: dundi precache <number>[@context]\n"
02505          "       Lookup the given number within the given DUNDi context\n"
02506          "(or e164 if none is specified) and precaches the results to any\n"
02507          "upstream DUNDi push servers.\n";
02508       return NULL;
02509    case CLI_GENERATE:
02510       return NULL;
02511    }
02512    if ((a->argc < 3) || (a->argc > 3)) {
02513       return CLI_SHOWUSAGE;
02514    }
02515    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02516    context = strchr(tmp, '@');
02517    if (context) {
02518       *context = '\0';
02519       context++;
02520    }
02521    start = ast_tvnow();
02522    res = dundi_precache(context, tmp);
02523 
02524    if (res < 0)
02525       ast_cli(a->fd, "DUNDi precache returned error.\n");
02526    else if (!res)
02527       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02528    ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02529    return CLI_SUCCESS;
02530 }

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

Definition at line 2532 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, NULL, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, dundi_entity_info::stateprov, tmp(), and ast_cli_entry::usage.

02533 {
02534    int res;
02535    char tmp[256];
02536    char *context;
02537    dundi_eid eid;
02538    struct dundi_entity_info dei;
02539    switch (cmd) {
02540    case CLI_INIT:
02541       e->command = "dundi query";
02542       e->usage =
02543          "Usage: dundi query <entity>[@context]\n"
02544          "       Attempts to retrieve contact information for a specific\n"
02545          "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
02546          "e164 if none is specified).\n";
02547       return NULL;
02548    case CLI_GENERATE:
02549       return NULL;
02550    }
02551    if ((a->argc < 3) || (a->argc > 3)) {
02552       return CLI_SHOWUSAGE;
02553    }
02554    if (ast_str_to_eid(&eid, a->argv[2])) {
02555       ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
02556       return CLI_SHOWUSAGE;
02557    }
02558    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02559    context = strchr(tmp, '@');
02560    if (context) {
02561       *context = '\0';
02562       context++;
02563    }
02564    res = dundi_query_eid(&dei, context, eid);
02565    if (res < 0)
02566       ast_cli(a->fd, "DUNDi Query EID returned error.\n");
02567    else if (!res)
02568       ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
02569    else {
02570       ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
02571       ast_cli(a->fd, "Department:      %s\n", dei.orgunit);
02572       ast_cli(a->fd, "Organization:    %s\n", dei.org);
02573       ast_cli(a->fd, "City/Locality:   %s\n", dei.locality);
02574       ast_cli(a->fd, "State/Province:  %s\n", dei.stateprov);
02575       ast_cli(a->fd, "Country:         %s\n", dei.country);
02576       ast_cli(a->fd, "E-mail:          %s\n", dei.email);
02577       ast_cli(a->fd, "Phone:           %s\n", dei.phone);
02578       ast_cli(a->fd, "IP Address:      %s\n", dei.ipaddr);
02579    }
02580    return CLI_SUCCESS;
02581 }

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

Definition at line 1422 of file pbx_dundi.c.

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

01423 {
01424    unsigned char *compress_space;
01425    int len;
01426    int res;
01427    unsigned long bytes;
01428    struct dundi_ie_data ied;
01429    struct dundi_peer *peer;
01430    unsigned char iv[16];
01431    len = pack->datalen + pack->datalen / 100 + 42;
01432    compress_space = ast_alloca(len);
01433    memset(compress_space, 0, len);
01434    /* We care about everthing save the first 6 bytes of header */
01435    bytes = len;
01436    res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
01437    if (res != Z_OK) {
01438       ast_debug(1, "Ouch, compression failed!\n");
01439       return -1;
01440    }
01441    memset(&ied, 0, sizeof(ied));
01442    /* Say who we are */
01443    if (!pack->h->iseqno && !pack->h->oseqno) {
01444       /* Need the key in the first copy */
01445       if (!(peer = find_peer(&trans->them_eid)))
01446          return -1;
01447       if (update_key(peer))
01448          return -1;
01449       if (!peer->sentfullkey)
01450          ast_set_flag(trans, FLAG_SENDFULLKEY);
01451       /* Append key data */
01452       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
01453       if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
01454          dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
01455          dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
01456       } else {
01457          dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
01458       }
01459       /* Setup contexts */
01460       trans->ecx = peer->us_ecx;
01461       trans->dcx = peer->us_dcx;
01462 
01463       /* We've sent the full key */
01464       peer->sentfullkey = 1;
01465    }
01466    /* Build initialization vector */
01467    build_iv(iv);
01468    /* Add the field, rounded up to 16 bytes */
01469    dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
01470    /* Copy the data */
01471    if ((ied.pos + bytes) >= sizeof(ied.buf)) {
01472       ast_log(LOG_NOTICE, "Final packet too large!\n");
01473       return -1;
01474    }
01475    encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
01476    ied.pos += ((bytes + 15) / 16) * 16;
01477    /* Reconstruct header */
01478    pack->datalen = sizeof(struct dundi_hdr);
01479    pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
01480    pack->h->cmdflags = 0;
01481    memcpy(pack->h->ies, ied.buf, ied.pos);
01482    pack->datalen += ied.pos;
01483    return 0;
01484 }

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

Definition at line 362 of file pbx_dundi.c.

References ast_log, and LOG_WARNING.

Referenced by load_module().

00363 {
00364    ast_log(LOG_WARNING, "%s", data);
00365 }

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

References ast_channel_exten(), ast_channel_macroexten(), ast_log, ast_strlen_zero, ast_test_flag, DUNDI_FLAG_EXISTS, dundi_lookup(), LOG_NOTICE, LOG_WARNING, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), S_OR, and sort_results().

04745 {
04746    struct dundi_result results[MAX_RESULTS];
04747    int res;
04748    int x=0;
04749    char req[1024];
04750    const char *dundiargs;
04751    struct ast_app *dial;
04752 
04753    if (!strncasecmp(context, "macro-", 6)) {
04754       if (!chan) {
04755          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04756          return -1;
04757       }
04758       /* If done as a macro, use macro extension */
04759       if (!strcasecmp(exten, "s")) {
04760          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04761          if (ast_strlen_zero(exten))
04762             exten = ast_channel_macroexten(chan);
04763          if (ast_strlen_zero(exten))
04764             exten = ast_channel_exten(chan);
04765          if (ast_strlen_zero(exten)) {
04766             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04767             return -1;
04768          }
04769       }
04770       if (ast_strlen_zero(data))
04771          data = "e164";
04772    } else {
04773       if (ast_strlen_zero(data))
04774          data = context;
04775    }
04776    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04777    if (res > 0) {
04778       sort_results(results, res);
04779       for (x=0;x<res;x++) {
04780          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04781             if (!--priority)
04782                break;
04783          }
04784       }
04785    }
04786    if (x < res) {
04787       /* Got a hit! */
04788       dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
04789       snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest,
04790          S_OR(dundiargs, ""));
04791       dial = pbx_findapp("Dial");
04792       if (dial)
04793          res = pbx_exec(chan, dial, req);
04794    } else
04795       res = -1;
04796    return res;
04797 }

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04735 {
04736    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04737 }

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

Definition at line 2338 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, NULL, and ast_cli_entry::usage.

02339 {
02340    int stats = 0;
02341    switch (cmd) {
02342    case CLI_INIT:
02343       e->command = "dundi flush [stats]";
02344       e->usage =
02345          "Usage: dundi flush [stats]\n"
02346          "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
02347          "'stats' is present, clears timer statistics instead of normal\n"
02348          "operation.\n";
02349       return NULL;
02350    case CLI_GENERATE:
02351       return NULL;
02352    }
02353    if ((a->argc < 2) || (a->argc > 3)) {
02354       return CLI_SHOWUSAGE;
02355    }
02356    if (a->argc > 2) {
02357       if (!strcasecmp(a->argv[2], "stats")) {
02358          stats = 1;
02359       } else {
02360          return CLI_SHOWUSAGE;
02361       }
02362    }
02363    if (stats) {
02364       /* Flush statistics */
02365       struct dundi_peer *p;
02366       int x;
02367       AST_LIST_LOCK(&peers);
02368       AST_LIST_TRAVERSE(&peers, p, list) {
02369          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02370             if (p->lookups[x])
02371                ast_free(p->lookups[x]);
02372             p->lookups[x] = NULL;
02373             p->lookuptimes[x] = 0;
02374          }
02375          p->avgms = 0;
02376       }
02377       AST_LIST_UNLOCK(&peers);
02378    } else {
02379       ast_db_deltree("dundi/cache", NULL);
02380       ast_cli(a->fd, "DUNDi Cache Flushed\n");
02381    }
02382    return CLI_SUCCESS;
02383 }

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

References ast_channel_exten(), ast_channel_macroexten(), ast_log, ast_strlen_zero, ast_test_flag, dundi_lookup(), LOG_NOTICE, LOG_WARNING, and pbx_builtin_getvar_helper().

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

04696 {
04697    struct dundi_result results[MAX_RESULTS];
04698    int res;
04699    int x;
04700    int found = 0;
04701    if (!strncasecmp(context, "macro-", 6)) {
04702       if (!chan) {
04703          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04704          return -1;
04705       }
04706       /* If done as a macro, use macro extension */
04707       if (!strcasecmp(exten, "s")) {
04708          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04709          if (ast_strlen_zero(exten))
04710             exten = ast_channel_macroexten(chan);
04711          if (ast_strlen_zero(exten))
04712             exten = ast_channel_exten(chan);
04713          if (ast_strlen_zero(exten)) {
04714             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04715             return -1;
04716          }
04717       }
04718       if (ast_strlen_zero(data))
04719          data = "e164";
04720    } else {
04721       if (ast_strlen_zero(data))
04722          data = context;
04723    }
04724    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04725    for (x=0;x<res;x++) {
04726       if (ast_test_flag(results + x, flag))
04727          found++;
04728    }
04729    if (found >= priority)
04730       return 1;
04731    return 0;
04732 }

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

Definition at line 3336 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().

03337 {
03338    struct dundi_peer *p;
03339    if (!ast_eid_cmp(eid, us)) {
03340       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03341       return;
03342    }
03343    AST_LIST_LOCK(&peers);
03344    AST_LIST_TRAVERSE(&peers, p, list) {
03345       if (!ast_eid_cmp(&p->eid, eid)) {
03346          if (has_permission(&p->include, context))
03347             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03348          else
03349             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03350          break;
03351       }
03352    }
03353    if (!p)
03354       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03355    AST_LIST_UNLOCK(&peers);
03356 }

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

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

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

03871 {
03872    struct dundi_hint_metadata hmd;
03873    dundi_eid *avoid[1] = { NULL, };
03874    int direct[1] = { 0, };
03875    int expiration = dundi_cache_time;
03876    memset(&hmd, 0, sizeof(hmd));
03877    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03878    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03879 }

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

References abort_request(), ast_channel_name(), 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, NULL, dundi_request::number, optimize_transactions(), order, 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().

03769 {
03770    int res;
03771    struct dundi_request dr, *pending;
03772    dundi_eid *rooteid=NULL;
03773    int x;
03774    int ttlms;
03775    int ms;
03776    int foundcache;
03777    int skipped=0;
03778    int order=0;
03779    char eid_str[20];
03780    struct timeval start;
03781 
03782    /* Don't do anthing for a hungup channel */
03783    if (chan && ast_check_hangup(chan))
03784       return 0;
03785 
03786    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03787 
03788    for (x=0;avoid[x];x++)
03789       rooteid = avoid[x];
03790    /* Now perform real check */
03791    memset(&dr, 0, sizeof(dr));
03792    if (pipe(dr.pfds)) {
03793       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03794       return -1;
03795    }
03796    dr.dr = result;
03797    dr.hmd = hmd;
03798    dr.maxcount = maxret;
03799    dr.expiration = *expiration;
03800    dr.cbypass = cbypass;
03801    dr.crc32 = avoid_crc32(avoid);
03802    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03803    ast_copy_string(dr.number, number, sizeof(dr.number));
03804    if (rooteid)
03805       dr.root_eid = *rooteid;
03806    res = register_request(&dr, &pending);
03807    if (res) {
03808       /* Already a request */
03809       if (rooteid && !ast_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03810          /* This is on behalf of someone else.  Go ahead and close this out since
03811             they'll get their answer anyway. */
03812          ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03813             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03814          close(dr.pfds[0]);
03815          close(dr.pfds[1]);
03816          return -2;
03817       } else {
03818          /* Wait for the cache to populate */
03819          ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n",
03820             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03821          start = ast_tvnow();
03822          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03823             /* XXX Would be nice to have a way to poll/select here XXX */
03824             /* XXX this is a busy wait loop!!! */
03825             usleep(1);
03826          }
03827          /* Continue on as normal, our cache should kick in */
03828       }
03829    }
03830    /* Create transactions */
03831    do {
03832       order = skipped;
03833       skipped = 0;
03834       foundcache = 0;
03835       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03836    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03837    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03838       do this earlier because we didn't know if we were going to have transactions
03839       or not. */
03840    if (!ttl) {
03841       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03842       abort_request(&dr);
03843       unregister_request(&dr);
03844       close(dr.pfds[0]);
03845       close(dr.pfds[1]);
03846       return 0;
03847    }
03848 
03849    /* Optimize transactions */
03850    optimize_transactions(&dr, order);
03851    /* Actually perform transactions */
03852    discover_transactions(&dr);
03853    /* Wait for transaction to come back */
03854    start = ast_tvnow();
03855    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03856       ms = 100;
03857       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03858    }
03859    if (chan && ast_check_hangup(chan))
03860       ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", ast_channel_name(chan), dr.number, dr.dcontext);
03861    cancel_request(&dr);
03862    unregister_request(&dr);
03863    res = dr.respcount;
03864    *expiration = dr.expiration;
03865    close(dr.pfds[0]);
03866    close(dr.pfds[1]);
03867    return res;
03868 }

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 576 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, NULL, dundi_mapping::options, pbx_substitute_variables_varshead(), dundi_result::tech, dundi_mapping::tech, tech2str(), dundi_result::techint, tmp(), and dundi_result::weight.

Referenced by dundi_lookup_thread(), and precache_trans().

00577 {
00578    struct ast_flags flags = {0};
00579    int x;
00580    if (!ast_strlen_zero(map->lcontext)) {
00581       if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00582          ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00583       if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00584          ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00585       if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00586          ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00587       if (ast_ignore_pattern(map->lcontext, called_number))
00588          ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00589 
00590       /* Clearly we can't say 'don't ask' anymore if we found anything... */
00591       if (ast_test_flag(&flags, AST_FLAGS_ALL))
00592          ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00593 
00594       if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00595          /* Skip partial answers */
00596          ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00597       }
00598       if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00599          struct varshead headp;
00600          struct ast_var_t *newvariable;
00601          ast_set_flag(&flags, map->options & 0xffff);
00602          ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00603          dr[anscnt].techint = map->tech;
00604          dr[anscnt].expiration = dundi_cache_time;
00605          ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00606          dr[anscnt].eid = *us_eid;
00607          ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00608          if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00609             AST_LIST_HEAD_INIT_NOLOCK(&headp);
00610             if ((newvariable = ast_var_assign("NUMBER", called_number))) {
00611                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00612             }
00613             if ((newvariable = ast_var_assign("EID", dr[anscnt].eid_str))) {
00614                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00615             }
00616             if ((newvariable = ast_var_assign("SECRET", cursecret))) {
00617                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00618             }
00619             if ((newvariable = ast_var_assign("IPADDR", ipaddr))) {
00620                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00621             }
00622             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00623             dr[anscnt].weight = get_mapping_weight(map, &headp);
00624             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00625                ast_var_delete(newvariable);
00626          } else {
00627             dr[anscnt].dest[0] = '\0';
00628             dr[anscnt].weight = get_mapping_weight(map, NULL);
00629          }
00630          anscnt++;
00631       } else {
00632          /* No answers...  Find the fewest number of digits from the
00633             number for which we have no answer. */
00634          char tmp[AST_MAX_EXTENSION + 1] = "";
00635          for (x = 0; x < (sizeof(tmp) - 1); x++) {
00636             tmp[x] = called_number[x];
00637             if (!tmp[x])
00638                break;
00639             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00640                /* Oops found something we can't match.  If this is longer
00641                   than the running hint, we have to consider it */
00642                if (strlen(tmp) > strlen(hmd->exten)) {
00643                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00644                }
00645                break;
00646             }
00647          }
00648       }
00649    }
00650    return anscnt;
00651 }

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

Definition at line 655 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, max, dundi_query_state::nocache, NULL, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, dundi_transaction::us_eid, dundi_result::weight, and weight.

Referenced by dundi_answer_query().

00656 {
00657    struct dundi_query_state *st = data;
00658    struct dundi_result dr[MAX_RESULTS];
00659    struct dundi_ie_data ied;
00660    struct dundi_hint_metadata hmd;
00661    char eid_str[20];
00662    int res, x;
00663    int ouranswers=0;
00664    int max = 999999;
00665    int expiration = dundi_cache_time;
00666 
00667    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00668          st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00669    memset(&ied, 0, sizeof(ied));
00670    memset(&dr, 0, sizeof(dr));
00671    memset(&hmd, 0, sizeof(hmd));
00672    /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
00673    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00674    for (x=0;x<st->nummaps;x++)
00675       ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00676    if (ouranswers < 0)
00677       ouranswers = 0;
00678    for (x=0;x<ouranswers;x++) {
00679       if (dr[x].weight < max)
00680          max = dr[x].weight;
00681    }
00682 
00683    if (max) {
00684       /* If we do not have a canonical result, keep looking */
00685       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);
00686       if (res > 0) {
00687          /* Append answer in result */
00688          ouranswers += res;
00689       } else {
00690          if ((res < -1) && (!ouranswers))
00691             dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00692       }
00693    }
00694    AST_LIST_LOCK(&peers);
00695    /* Truncate if "don't ask" isn't present */
00696    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00697       hmd.exten[0] = '\0';
00698    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00699       ast_debug(1, "Our transaction went away!\n");
00700       st->trans->thread = 0;
00701       destroy_trans(st->trans, 0);
00702    } else {
00703       for (x=0;x<ouranswers;x++) {
00704          /* Add answers */
00705          if (dr[x].expiration && (expiration > dr[x].expiration))
00706             expiration = dr[x].expiration;
00707          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00708       }
00709       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00710       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00711       dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00712       st->trans->thread = 0;
00713    }
00714    AST_LIST_UNLOCK(&peers);
00715    ast_free(st);
00716    return NULL;
00717 }

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04800 {
04801    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04802 }

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

Pre-cache to push upstream peers.

Definition at line 4013 of file pbx_dundi.c.

References dundi_precache_internal(), and NULL.

Referenced by dundi_do_precache(), and process_precache().

04014 {
04015    dundi_eid *avoid[1] = { NULL, };
04016    return dundi_precache_internal(context, number, dundi_ttl, avoid);
04017 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3917 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, e, dundi_mapping::lcontext, LOG_NOTICE, NULL, and reschedule_precache().

Referenced by set_config().

03918 {
03919    struct dundi_mapping *cur;
03920    struct ast_context *con;
03921    struct ast_exten *e;
03922 
03923    AST_LIST_TRAVERSE(&mappings, cur, list) {
03924       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03925       ast_rdlock_contexts();
03926       con = NULL;
03927       while ((con = ast_walk_contexts(con))) {
03928          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03929             continue;
03930          /* Found the match, now queue them all up */
03931          ast_rdlock_context(con);
03932          e = NULL;
03933          while ((e = ast_walk_context_extensions(con, e)))
03934             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03935          ast_unlock_context(con);
03936       }
03937       ast_unlock_contexts();
03938    }
03939 }

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

Definition at line 3941 of file pbx_dundi.c.

References ast_alloca, 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, NULL, dundi_request::number, optimize_transactions(), dundi_request::pfds, precache_transactions(), reschedule_precache(), and dundi_request::trans.

Referenced by dundi_precache(), and dundi_precache_thread().

03942 {
03943    struct dundi_request dr;
03944    struct dundi_hint_metadata hmd;
03945    struct dundi_result dr2[MAX_RESULTS];
03946    struct timeval start;
03947    struct dundi_mapping *maps = NULL, *cur;
03948    int nummaps = 0;
03949    int foundanswers;
03950    int foundcache, skipped, ttlms, ms;
03951    if (!context)
03952       context = "e164";
03953    ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
03954 
03955    AST_LIST_LOCK(&peers);
03956    AST_LIST_TRAVERSE(&mappings, cur, list) {
03957       if (!strcasecmp(cur->dcontext, context))
03958          nummaps++;
03959    }
03960    if (nummaps) {
03961       maps = ast_alloca(nummaps * sizeof(*maps));
03962       nummaps = 0;
03963       AST_LIST_TRAVERSE(&mappings, cur, list) {
03964          if (!strcasecmp(cur->dcontext, context))
03965             maps[nummaps++] = *cur;
03966       }
03967    }
03968    AST_LIST_UNLOCK(&peers);
03969    if (!nummaps) {
03970       return -1;
03971    }
03972    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03973    memset(&dr2, 0, sizeof(dr2));
03974    memset(&dr, 0, sizeof(dr));
03975    memset(&hmd, 0, sizeof(hmd));
03976    dr.dr = dr2;
03977    ast_copy_string(dr.number, number, sizeof(dr.number));
03978    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03979    dr.maxcount = MAX_RESULTS;
03980    dr.expiration = dundi_cache_time;
03981    dr.hmd = &hmd;
03982    dr.pfds[0] = dr.pfds[1] = -1;
03983    if (pipe(dr.pfds) < 0) {
03984       ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno));
03985       return -1;
03986    }
03987    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03988    optimize_transactions(&dr, 0);
03989    foundanswers = 0;
03990    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03991    if (foundanswers) {
03992       if (dr.expiration > 0)
03993          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03994       else
03995          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03996    }
03997    start = ast_tvnow();
03998    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03999       if (dr.pfds[0] > -1) {
04000          ms = 100;
04001          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
04002       } else
04003          usleep(1);
04004    }
04005    cancel_request(&dr);
04006    if (dr.pfds[0] > -1) {
04007       close(dr.pfds[0]);
04008       close(dr.pfds[1]);
04009    }
04010    return 0;
04011 }

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

Definition at line 719 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, NULL, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

Referenced by dundi_prop_precache().

00720 {
00721    struct dundi_query_state *st = data;
00722    struct dundi_ie_data ied;
00723    struct dundi_hint_metadata hmd;
00724    char eid_str[20];
00725 
00726    ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
00727       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00728    memset(&ied, 0, sizeof(ied));
00729 
00730    /* Now produce precache */
00731    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00732 
00733    AST_LIST_LOCK(&peers);
00734    /* Truncate if "don't ask" isn't present */
00735    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00736       hmd.exten[0] = '\0';
00737    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00738       ast_debug(1, "Our transaction went away!\n");
00739       st->trans->thread = 0;
00740       destroy_trans(st->trans, 0);
00741    } else {
00742       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00743       st->trans->thread = 0;
00744    }
00745    AST_LIST_UNLOCK(&peers);
00746    ast_free(st);
00747    return NULL;
00748 }

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

Definition at line 938 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, NULL, dundi_request::number, dundi_query_state::nummaps, dundi_transaction::parent, dundi_request::pfds, dundi_answer::protocol, dundi_request::respcount, 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().

00939 {
00940    struct dundi_query_state *st;
00941    int totallen;
00942    int x,z;
00943    struct dundi_ie_data ied;
00944    char *s;
00945    struct dundi_result dr2[MAX_RESULTS];
00946    struct dundi_request dr;
00947    struct dundi_hint_metadata hmd;
00948 
00949    struct dundi_mapping *cur;
00950    int mapcount;
00951    int skipfirst = 0;
00952 
00953    pthread_t lookupthread;
00954 
00955    memset(&dr2, 0, sizeof(dr2));
00956    memset(&dr, 0, sizeof(dr));
00957    memset(&hmd, 0, sizeof(hmd));
00958 
00959    /* Forge request structure to hold answers for cache */
00960    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00961    dr.dr = dr2;
00962    dr.maxcount = MAX_RESULTS;
00963    dr.expiration = dundi_cache_time;
00964    dr.hmd = &hmd;
00965    dr.pfds[0] = dr.pfds[1] = -1;
00966    trans->parent = &dr;
00967    ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
00968    ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
00969 
00970    for (x=0;x<ies->anscount;x++) {
00971       if (trans->parent->respcount < trans->parent->maxcount) {
00972          /* Make sure it's not already there */
00973          for (z=0;z<trans->parent->respcount;z++) {
00974             if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
00975                 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data))
00976                   break;
00977          }
00978          if (z == trans->parent->respcount) {
00979             /* Copy into parent responses */
00980             trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
00981             trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
00982             trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
00983             trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
00984             if (ies->expiration > 0)
00985                trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
00986             else
00987                trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
00988             ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
00989                sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
00990                &ies->answers[x]->eid);
00991             ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
00992                sizeof(trans->parent->dr[trans->parent->respcount].dest));
00993                ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
00994                sizeof(trans->parent->dr[trans->parent->respcount].tech));
00995             trans->parent->respcount++;
00996             ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
00997          } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
00998             /* Update weight if appropriate */
00999             trans->parent->dr[z].weight = ies->answers[x]->weight;
01000          }
01001       } else
01002          ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
01003             trans->parent->number, trans->parent->dcontext);
01004 
01005    }
01006    /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
01007    cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
01008    if (ies->hint)
01009       cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
01010 
01011    totallen = sizeof(struct dundi_query_state);
01012    /* Count matching map entries */
01013    mapcount = 0;
01014    AST_LIST_TRAVERSE(&mappings, cur, list) {
01015       if (!strcasecmp(cur->dcontext, ccontext))
01016          mapcount++;
01017    }
01018 
01019    /* If no maps, return -1 immediately */
01020    if (!mapcount)
01021       return -1;
01022 
01023    if (ies->eidcount > 1) {
01024       /* Since it is a requirement that the first EID is the authenticating host
01025          and the last EID is the root, it is permissible that the first and last EID
01026          could be the same.  In that case, we should go ahead copy only the "root" section
01027          since we will not need it for authentication. */
01028       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01029          skipfirst = 1;
01030    }
01031 
01032    /* Prepare to run a query and then propagate that as necessary */
01033    totallen += mapcount * sizeof(struct dundi_mapping);
01034    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01035    st = ast_calloc(1, totallen);
01036    if (st) {
01037       ast_copy_string(st->called_context, dr.dcontext, sizeof(st->called_context));
01038       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01039       st->trans = trans;
01040       st->ttl = ies->ttl - 1;
01041       st->nocache = ies->cbypass;
01042       if (st->ttl < 0)
01043          st->ttl = 0;
01044       s = st->fluffy;
01045       for (x=skipfirst;ies->eids[x];x++) {
01046          st->eids[x-skipfirst] = (dundi_eid *)s;
01047          *st->eids[x-skipfirst] = *ies->eids[x];
01048          st->directs[x-skipfirst] = ies->eid_direct[x];
01049          s += sizeof(dundi_eid);
01050       }
01051       /* Append mappings */
01052       x = 0;
01053       st->maps = (struct dundi_mapping *)s;
01054       AST_LIST_TRAVERSE(&mappings, cur, list) {
01055          if (!strcasecmp(cur->dcontext, ccontext)) {
01056             if (x < mapcount) {
01057                st->maps[x] = *cur;
01058                st->maps[x].list.next = NULL;
01059                x++;
01060             }
01061          }
01062       }
01063       st->nummaps = mapcount;
01064       ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
01065       trans->thread = 1;
01066       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
01067          trans->thread = 0;
01068          ast_log(LOG_WARNING, "Unable to create thread!\n");
01069          ast_free(st);
01070          memset(&ied, 0, sizeof(ied));
01071          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01072          dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
01073          return -1;
01074       }
01075    } else {
01076       ast_log(LOG_WARNING, "Out of memory!\n");
01077       memset(&ied, 0, sizeof(ied));
01078       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01079       dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
01080       return -1;
01081    }
01082    return 0;
01083 }

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3448 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().

03449 {
03450    struct dundi_ie_data ied;
03451    int x;
03452    if (!trans->parent) {
03453       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03454       return -1;
03455    }
03456    memset(&ied, 0, sizeof(ied));
03457    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03458    if (!dundi_eid_zero(&trans->us_eid))
03459       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03460    for (x=0;x<trans->eidcount;x++)
03461       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03462    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03463    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03464    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03465    if (trans->autokilltimeout)
03466       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03467    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03468 }

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

Retrieve information on a specific EID.

Definition at line 4066 of file pbx_dundi.c.

References dundi_query_eid_internal(), and NULL.

Referenced by dundi_do_query().

04067 {
04068    dundi_eid *avoid[1] = { NULL, };
04069    struct dundi_hint_metadata hmd;
04070    memset(&hmd, 0, sizeof(hmd));
04071    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
04072 }

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 4019 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, NULL, 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().

04020 {
04021    int res;
04022    struct dundi_request dr;
04023    dundi_eid *rooteid=NULL;
04024    int x;
04025    int ttlms;
04026    int skipped=0;
04027    int foundcache=0;
04028    struct timeval start;
04029 
04030    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
04031 
04032    for (x=0;avoid[x];x++)
04033       rooteid = avoid[x];
04034    /* Now perform real check */
04035    memset(&dr, 0, sizeof(dr));
04036    dr.hmd = hmd;
04037    dr.dei = dei;
04038    dr.pfds[0] = dr.pfds[1] = -1;
04039    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
04040    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
04041    if (rooteid)
04042       dr.root_eid = *rooteid;
04043    /* Create transactions */
04044    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
04045 
04046    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
04047       do this earlier because we didn't know if we were going to have transactions
04048       or not. */
04049    if (!ttl) {
04050       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
04051       return 0;
04052    }
04053 
04054    /* Optimize transactions */
04055    optimize_transactions(&dr, 9999);
04056    /* Actually perform transactions */
04057    query_transactions(&dr);
04058    /* Wait for transaction to come back */
04059    start = ast_tvnow();
04060    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
04061       usleep(1);
04062    res = dr.respcount;
04063    return res;
04064 }

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

Definition at line 4160 of file pbx_dundi.c.

References args, 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_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, NULL, dundi_result_datastore::num_results, OPT_BYPASS_CACHE, parse(), dundi_result_datastore::results, and sort_results().

04161 {
04162    AST_DECLARE_APP_ARGS(args,
04163       AST_APP_ARG(number);
04164       AST_APP_ARG(context);
04165       AST_APP_ARG(options);
04166    );
04167    struct ast_flags opts = { 0, };
04168    char *parse;
04169    struct dundi_result_datastore *drds;
04170    struct ast_datastore *datastore;
04171 
04172    if (ast_strlen_zero(data)) {
04173       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
04174       return -1;
04175    }
04176 
04177    if (!chan) {
04178       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
04179       return -1;
04180    }
04181 
04182    parse = ast_strdupa(data);
04183 
04184    AST_STANDARD_APP_ARGS(args, parse);
04185 
04186    if (!ast_strlen_zero(args.options))
04187       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
04188 
04189    if (ast_strlen_zero(args.context))
04190       args.context = "e164";
04191 
04192    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
04193       return -1;
04194    }
04195 
04196    drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
04197    snprintf(buf, len, "%u", drds->id);
04198 
04199    if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) {
04200       drds_destroy(drds);
04201       return -1;
04202    }
04203 
04204    datastore->data = drds;
04205 
04206    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context,
04207       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04208 
04209    if (drds->num_results > 0)
04210       sort_results(drds->results, drds->num_results);
04211 
04212    ast_channel_lock(chan);
04213    ast_channel_datastore_add(chan, datastore);
04214    ast_channel_unlock(chan);
04215 
04216    return 0;
04217 }

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

Definition at line 752 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, NULL, 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().

00753 {
00754    struct dundi_query_state *st = data;
00755    struct dundi_entity_info dei;
00756    struct dundi_ie_data ied;
00757    struct dundi_hint_metadata hmd;
00758    char eid_str[20];
00759    int res;
00760 
00761    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00762       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00763    memset(&ied, 0, sizeof(ied));
00764    memset(&dei, 0, sizeof(dei));
00765    memset(&hmd, 0, sizeof(hmd));
00766    if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00767       /* Ooh, it's us! */
00768       ast_debug(1, "Neat, someone look for us!\n");
00769       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00770       ast_copy_string(dei.org, org, sizeof(dei.org));
00771       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00772       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00773       ast_copy_string(dei.country, country, sizeof(dei.country));
00774       ast_copy_string(dei.email, email, sizeof(dei.email));
00775       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00776       res = 1;
00777    } else {
00778       /* If we do not have a canonical result, keep looking */
00779       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00780    }
00781    AST_LIST_LOCK(&peers);
00782    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00783       ast_debug(1, "Our transaction went away!\n");
00784       st->trans->thread = 0;
00785       destroy_trans(st->trans, 0);
00786    } else {
00787       if (res) {
00788          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00789          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00790          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00791          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00792          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00793          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00794          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00795          if (!ast_strlen_zero(dei.ipaddr))
00796             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00797       }
00798       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00799       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00800       st->trans->thread = 0;
00801    }
00802    AST_LIST_UNLOCK(&peers);
00803    ast_free(st);
00804    return NULL;
00805 }

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

Definition at line 453 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, dundi_hdr::strans, and tmp().

Referenced by handle_frame().

00454 {
00455    struct {
00456       struct dundi_packet pack;
00457       struct dundi_hdr hdr;
00458    } tmp;
00459    struct dundi_transaction trans;
00460    /* Never respond to an INVALID with another INVALID */
00461    if (h->cmdresp == DUNDI_COMMAND_INVALID)
00462       return;
00463    memset(&tmp, 0, sizeof(tmp));
00464    memset(&trans, 0, sizeof(trans));
00465    memcpy(&trans.addr, sin, sizeof(trans.addr));
00466    tmp.hdr.strans = h->dtrans;
00467    tmp.hdr.dtrans = h->strans;
00468    tmp.hdr.iseqno = h->oseqno;
00469    tmp.hdr.oseqno = h->iseqno;
00470    tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00471    tmp.hdr.cmdflags = 0;
00472    tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00473    tmp.pack.datalen = sizeof(struct dundi_hdr);
00474    tmp.pack.parent = &trans;
00475    dundi_xmit(&tmp.pack);
00476 }

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

Definition at line 4224 of file pbx_dundi.c.

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

04225 {
04226    AST_DECLARE_APP_ARGS(args,
04227       AST_APP_ARG(id);
04228       AST_APP_ARG(resultnum);
04229    );
04230    char *parse;
04231    unsigned int num;
04232    struct dundi_result_datastore *drds;
04233    struct ast_datastore *datastore;
04234    int res = -1;
04235 
04236    if (ast_strlen_zero(data)) {
04237       ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n");
04238       goto finish;
04239    }
04240 
04241    if (!chan) {
04242       ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n");
04243       goto finish;
04244    }
04245 
04246    parse = ast_strdupa(data);
04247 
04248    AST_STANDARD_APP_ARGS(args, parse);
04249 
04250    if (ast_strlen_zero(args.id)) {
04251       ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n");
04252       goto finish;
04253    }
04254 
04255    if (ast_strlen_zero(args.resultnum)) {
04256       ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n");
04257       goto finish;
04258    }
04259 
04260    ast_channel_lock(chan);
04261    datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id);
04262    ast_channel_unlock(chan);
04263 
04264    if (!datastore) {
04265       ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id);
04266       goto finish;
04267    }
04268 
04269    drds = datastore->data;
04270 
04271    if (!strcasecmp(args.resultnum, "getnum")) {
04272       snprintf(buf, len, "%u", drds->num_results);
04273       res = 0;
04274       goto finish;
04275    }
04276 
04277    if (sscanf(args.resultnum, "%30u", &num) != 1) {
04278       ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n",
04279          args.resultnum);
04280       goto finish;
04281    }
04282 
04283    if (num && num <= drds->num_results) {
04284       snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest);
04285       res = 0;
04286    } else
04287       ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id);
04288 
04289 finish:
04290    return res;
04291 }

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

Definition at line 3231 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().

03232 {
03233    struct dundi_packet *pack = (struct dundi_packet *)data;
03234    int res;
03235    AST_LIST_LOCK(&peers);
03236    if (pack->retrans < 1) {
03237       pack->retransid = -1;
03238       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
03239          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",
03240             ast_inet_ntoa(pack->parent->addr.sin_addr),
03241             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
03242       destroy_trans(pack->parent, 1);
03243       res = 0;
03244    } else {
03245       /* Decrement retransmission, try again */
03246       pack->retrans--;
03247       dundi_xmit(pack);
03248       res = 1;
03249    }
03250    AST_LIST_UNLOCK(&peers);
03251    return res;
03252 }

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

Definition at line 3254 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().

03255 {
03256    struct dundi_packet *pack;
03257    int res;
03258    int len;
03259    char eid_str[20];
03260    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
03261    /* Reserve enough space for encryption */
03262    if (ast_test_flag(trans, FLAG_ENCRYPT))
03263       len += 384;
03264    pack = ast_calloc(1, len);
03265    if (pack) {
03266       pack->h = (struct dundi_hdr *)(pack->data);
03267       if (cmdresp != DUNDI_COMMAND_ACK) {
03268          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
03269          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
03270          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
03271       }
03272       pack->parent = trans;
03273       pack->h->strans = htons(trans->strans);
03274       pack->h->dtrans = htons(trans->dtrans);
03275       pack->h->iseqno = trans->iseqno;
03276       pack->h->oseqno = trans->oseqno;
03277       pack->h->cmdresp = cmdresp;
03278       pack->datalen = sizeof(struct dundi_hdr);
03279       if (ied) {
03280          memcpy(pack->h->ies, ied->buf, ied->pos);
03281          pack->datalen += ied->pos;
03282       }
03283       if (final) {
03284          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
03285          ast_set_flag(trans, FLAG_FINAL);
03286       }
03287       pack->h->cmdflags = flags;
03288       if (cmdresp != DUNDI_COMMAND_ACK) {
03289          trans->oseqno++;
03290          trans->oseqno = trans->oseqno % 256;
03291       }
03292       trans->aseqno = trans->iseqno;
03293       /* If we have their public key, encrypt */
03294       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
03295          switch(cmdresp) {
03296          case DUNDI_COMMAND_REGREQ:
03297          case DUNDI_COMMAND_REGRESPONSE:
03298          case DUNDI_COMMAND_DPDISCOVER:
03299          case DUNDI_COMMAND_DPRESPONSE:
03300          case DUNDI_COMMAND_EIDQUERY:
03301          case DUNDI_COMMAND_EIDRESPONSE:
03302          case DUNDI_COMMAND_PRECACHERQ:
03303          case DUNDI_COMMAND_PRECACHERP:
03304             if (dundidebug)
03305                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
03306             res = dundi_encrypt(trans, pack);
03307             break;
03308          default:
03309             res = 0;
03310          }
03311       } else
03312          res = 0;
03313       if (!res)
03314          res = dundi_xmit(pack);
03315       if (res)
03316          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03317 
03318       if (cmdresp == DUNDI_COMMAND_ACK)
03319          ast_free(pack);
03320       return res;
03321    }
03322    return -1;
03323 }

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

Definition at line 2285 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, NULL, and ast_cli_entry::usage.

02286 {
02287    switch (cmd) {
02288    case CLI_INIT:
02289       e->command = "dundi set debug {on|off}";
02290       e->usage =
02291          "Usage: dundi set debug {on|off}\n"
02292          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02293       return NULL;
02294    case CLI_GENERATE:
02295       return NULL;
02296    }
02297 
02298    if (a->argc != e->args) {
02299       return CLI_SHOWUSAGE;
02300    }
02301    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02302       dundidebug = 1;
02303       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02304    } else {
02305       dundidebug = 0;
02306       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02307    }
02308    return CLI_SUCCESS;
02309 }

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

Definition at line 2914 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), ast_db_freetree(), ast_db_gettree(), ast_eid_to_str(), ast_get_time_t(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_db_entry::data, dundi_eid_zero(), dundi_flags2str(), dundi_str_short_to_eid(), ast_cli_args::fd, ast_flags::flags, FORMAT, FORMAT2, ast_db_entry::key, ast_db_entry::next, NULL, tech2str(), ast_cli_entry::usage, and weight.

02915 {
02916 #define FORMAT2 "%-12.12s %-16.16s %-10.10s  %-18s %-7s %s\n"
02917 #define FORMAT "%-12.12s %-16.16s %6d sec  %-18s %-7d %s/%s (%s)\n"
02918         struct ast_db_entry *db_tree, *db_entry;
02919    int cnt = 0;
02920    time_t ts, now;
02921    dundi_eid src_eid;
02922    char src_eid_str[20];
02923    int expiry, tech, weight;
02924    struct ast_flags flags;
02925    char fs[256];
02926    int length;
02927    char *ptr, *term, *src, *number, *context, *dst;
02928 
02929    switch (cmd) {
02930    case CLI_INIT:
02931       e->command = "dundi show cache";
02932       e->usage =
02933       "Usage: dundi show cache\n"
02934       "       Lists all DUNDi cache entries.\n";
02935       return NULL;
02936    case CLI_GENERATE:
02937       return NULL;
02938    }
02939 
02940    if (a->argc != 3) {
02941       return CLI_SHOWUSAGE;
02942    }
02943 
02944    time(&now);
02945    db_tree = ast_db_gettree("dundi/cache", NULL);
02946    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration", "From", "Weight", "Destination (Flags)");
02947    for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
02948       if ((strncmp(db_entry->key, "/dundi/cache/hint/", 18) == 0) || ast_get_time_t(db_entry->data, &ts, 0, &length)) {
02949          continue;
02950       }
02951 
02952       expiry = ts - now;
02953 
02954       if (expiry <= 0) {
02955          continue;
02956       }
02957 
02958       ptr = db_entry->key + sizeof("/dundi/cache");
02959       strtok(ptr, "/");
02960       number = strtok(NULL, "/");
02961       context = strtok(NULL, "/");
02962       ptr = strtok(NULL, "/");
02963 
02964       if (*ptr != 'e') {
02965          continue;
02966       }
02967 
02968       ptr = db_entry->data + length + 1;
02969 
02970       if ((sscanf(ptr, "%30u/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) != 3)) {
02971          continue;
02972       }
02973 
02974       ptr += length;
02975       dst = ptr;
02976       term = strchr(ptr, '|');
02977 
02978       if (!term) {
02979          continue;
02980       }
02981 
02982       /* Ok, at this point we know we aren't going to skp the entry, so we go ahead and increment the count. */
02983       cnt++;
02984 
02985       *term = '\0';
02986       src = strrchr(ptr, '/');
02987       dundi_eid_zero(&src_eid);
02988 
02989       if (src) {
02990          *src = '\0';
02991          src++;
02992          dundi_str_short_to_eid(&src_eid, src);
02993          ast_eid_to_str(src_eid_str, sizeof(src_eid_str), &src_eid);
02994       }
02995 
02996       ast_cli(a->fd, FORMAT, number, context, expiry, src_eid_str, weight, tech2str(tech), dst, dundi_flags2str(fs, sizeof(fs), flags.flags));
02997    }
02998 
02999    ast_cli(a->fd, "Number of entries: %d\n", cnt);
03000    ast_db_freetree(db_tree);
03001 
03002    return CLI_SUCCESS;
03003 #undef FORMAT
03004 #undef FORMAT2
03005 }

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

Definition at line 2786 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, NULL, and ast_cli_entry::usage.

02787 {
02788    char eid_str[20];
02789    switch (cmd) {
02790    case CLI_INIT:
02791       e->command = "dundi show entityid";
02792       e->usage =
02793          "Usage: dundi show entityid\n"
02794          "       Displays the global entityid for this host.\n";
02795       return NULL;
02796    case CLI_GENERATE:
02797       return NULL;
02798    }
02799    if (a->argc != 3) {
02800       return CLI_SHOWUSAGE;
02801    }
02802    AST_LIST_LOCK(&peers);
02803    ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02804    AST_LIST_UNLOCK(&peers);
02805    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02806    return CLI_SUCCESS;
02807 }

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

Definition at line 3007 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), ast_db_freetree(), ast_db_gettree(), ast_eid_to_str(), ast_get_time_t(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_db_entry::data, dundi_str_short_to_eid(), ast_cli_args::fd, FORMAT, FORMAT2, ast_db_entry::key, ast_db_entry::next, NULL, and ast_cli_entry::usage.

03008 {
03009 #define FORMAT2 "%-12.12s %-16.16s %-10.10s  %-18s\n"
03010 #define FORMAT "%-12.12s %-16.16s %6d sec  %-18s\n"
03011    struct ast_db_entry *db_tree, *db_entry;
03012    int cnt = 0;
03013    time_t ts, now;
03014    dundi_eid src_eid;
03015    char src_eid_str[20];
03016    int expiry;
03017    int length;
03018    char *ptr, *src, *number, *context;
03019 
03020    switch (cmd) {
03021    case CLI_INIT:
03022       e->command = "dundi show hints";
03023       e->usage =
03024          "Usage: dundi show hints\n"
03025          "       Lists all DUNDi 'DONTASK' hints in the cache.\n";
03026       return NULL;
03027    case CLI_GENERATE:
03028       return NULL;
03029    }
03030 
03031    if (a->argc != 3) {
03032       return CLI_SHOWUSAGE;
03033    }
03034 
03035    time(&now);
03036    db_tree = ast_db_gettree("dundi/cache/hint", NULL);
03037    ast_cli(a->fd, FORMAT2, "Prefix", "Context", "Expiration", "From");
03038 
03039    for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
03040       if (ast_get_time_t(db_entry->data, &ts, 0, &length)) {
03041          continue;
03042       }
03043 
03044       expiry = ts - now;
03045 
03046       if (expiry <= 0) {
03047          continue;
03048       }
03049 
03050       ptr = db_entry->key + sizeof("/dundi/cache/hint");
03051       src = strtok(ptr, "/");
03052       number = strtok(NULL, "/");
03053       context = strtok(NULL, "/");
03054       ptr = strtok(NULL, "/");
03055 
03056       if (*ptr != 'e') {
03057          continue;
03058       }
03059 
03060       cnt++;
03061       dundi_str_short_to_eid(&src_eid, src);
03062       ast_eid_to_str(src_eid_str, sizeof(src_eid_str), &src_eid);
03063       ast_cli(a->fd, FORMAT, number, context, expiry, src_eid_str);
03064    }
03065 
03066    ast_cli(a->fd, "Number of entries: %d\n", cnt);
03067    ast_db_freetree(db_tree);
03068 
03069    return CLI_SUCCESS;
03070 #undef FORMAT
03071 #undef FORMAT2
03072 }

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

Definition at line 2842 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, NULL, dundi_mapping::options, dundi_mapping::tech, tech2str(), ast_cli_entry::usage, and weight.

02843 {
02844 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02845 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02846    struct dundi_mapping *map;
02847    char fs[256];
02848    char weight[8];
02849    switch (cmd) {
02850    case CLI_INIT:
02851       e->command = "dundi show mappings";
02852       e->usage =
02853          "Usage: dundi show mappings\n"
02854          "       Lists all known DUNDi mappings.\n";
02855       return NULL;
02856    case CLI_GENERATE:
02857       return NULL;
02858    }
02859    if (a->argc != 3) {
02860       return CLI_SHOWUSAGE;
02861    }
02862    AST_LIST_LOCK(&peers);
02863    ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02864    AST_LIST_TRAVERSE(&mappings, map, list) {
02865       snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map, NULL));
02866       ast_cli(a->fd, FORMAT, map->dcontext, weight,
02867          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext,
02868          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02869    }
02870    AST_LIST_UNLOCK(&peers);
02871    return CLI_SUCCESS;
02872 #undef FORMAT
02873 #undef FORMAT2
02874 }

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

Definition at line 2583 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, NULL, dundi_peer::order, order, dundi_peer::outkey, dundi_peer::permit, ast_cli_args::pos, dundi_peer::registerid, ast_cli_entry::usage, and ast_cli_args::word.

02584 {
02585    struct dundi_peer *peer;
02586    struct permission *p;
02587    char *order;
02588    char eid_str[20];
02589    int x, cnt;
02590    switch (cmd) {
02591    case CLI_INIT:
02592       e->command = "dundi show peer";
02593       e->usage =
02594          "Usage: dundi show peer [peer]\n"
02595          "       Provide a detailed description of a specifid DUNDi peer.\n";
02596       return NULL;
02597    case CLI_GENERATE:
02598       return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
02599    }
02600    if (a->argc != 4) {
02601       return CLI_SHOWUSAGE;
02602    }
02603    AST_LIST_LOCK(&peers);
02604    AST_LIST_TRAVERSE(&peers, peer, list) {
02605       if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
02606          break;
02607    }
02608    if (peer) {
02609       switch(peer->order) {
02610       case 0:
02611          order = "Primary";
02612          break;
02613       case 1:
02614          order = "Secondary";
02615          break;
02616       case 2:
02617          order = "Tertiary";
02618          break;
02619       case 3:
02620          order = "Quartiary";
02621          break;
02622       default:
02623          order = "Unknown";
02624       }
02625       ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02626       ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));
02627       ast_cli(a->fd, "Order:   %s\n", order);
02628       ast_cli(a->fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02629       ast_cli(a->fd, "Port:    %d\n", ntohs(peer->addr.sin_port));
02630       ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02631       ast_cli(a->fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02632       ast_cli(a->fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02633       ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02634       if (!AST_LIST_EMPTY(&peer->include))
02635          ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02636       AST_LIST_TRAVERSE(&peer->include, p, list)
02637          ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02638       if (!AST_LIST_EMPTY(&peer->permit))
02639          ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02640       AST_LIST_TRAVERSE(&peer->permit, p, list)
02641          ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02642       cnt = 0;
02643       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02644          if (peer->lookups[x]) {
02645             if (!cnt)
02646                ast_cli(a->fd, "Last few query times:\n");
02647             ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02648             cnt++;
02649          }
02650       }
02651       if (cnt)
02652          ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms);
02653    } else
02654       ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]);
02655    AST_LIST_UNLOCK(&peers);
02656    return CLI_SUCCESS;
02657 }

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

Definition at line 2659 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(), NULL, status, and ast_cli_entry::usage.

02660 {
02661 #define FORMAT2 "%-20.20s %-15.15s     %-6.6s %-10.10s %-8.8s %-15.15s\n"
02662 #define FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n"
02663    struct dundi_peer *peer;
02664    int registeredonly=0;
02665    char avgms[20];
02666    char eid_str[20];
02667    int online_peers = 0;
02668    int offline_peers = 0;
02669    int unmonitored_peers = 0;
02670    int total_peers = 0;
02671    switch (cmd) {
02672    case CLI_INIT:
02673       e->command = "dundi show peers [registered|include|exclude|begin]";
02674       e->usage =
02675          "Usage: dundi show peers [registered|include|exclude|begin]\n"
02676          "       Lists all known DUNDi peers.\n"
02677          "       If 'registered' is present, only registered peers are shown.\n";
02678       return NULL;
02679    case CLI_GENERATE:
02680       return NULL;
02681    }
02682 
02683    if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5)) {
02684       return CLI_SHOWUSAGE;
02685    }
02686    if ((a->argc == 4)) {
02687       if (!strcasecmp(a->argv[3], "registered")) {
02688          registeredonly = 1;
02689       } else {
02690          return CLI_SHOWUSAGE;
02691       }
02692    }
02693    AST_LIST_LOCK(&peers);
02694    ast_cli(a->fd, FORMAT2, "EID", "Host", "Port", "Model", "AvgTime", "Status");
02695    AST_LIST_TRAVERSE(&peers, peer, list) {
02696       char status[20];
02697       int print_line = -1;
02698       char srch[2000];
02699       total_peers++;
02700       if (registeredonly && !peer->addr.sin_addr.s_addr)
02701          continue;
02702       if (peer->maxms) {
02703          if (peer->lastms < 0) {
02704             strcpy(status, "UNREACHABLE");
02705             offline_peers++;
02706          }
02707          else if (peer->lastms > peer->maxms) {
02708             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02709             offline_peers++;
02710          }
02711          else if (peer->lastms) {
02712             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02713             online_peers++;
02714          }
02715          else {
02716             strcpy(status, "UNKNOWN");
02717             offline_peers++;
02718          }
02719       } else {
02720          strcpy(status, "Unmonitored");
02721          unmonitored_peers++;
02722       }
02723       if (peer->avgms)
02724          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02725       else
02726          strcpy(avgms, "Unavail");
02727       snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
02728                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02729                peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);
02730 
02731                 if (a->argc == 5) {
02732                   if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {
02733                         print_line = -1;
02734                    } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) {
02735                         print_line = 1;
02736                    } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) {
02737                         print_line = -1;
02738                    } else {
02739                         print_line = 0;
02740                   }
02741                 }
02742 
02743         if (print_line) {
02744          ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
02745                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02746                peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);
02747       }
02748    }
02749    ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02750    AST_LIST_UNLOCK(&peers);
02751    return CLI_SUCCESS;
02752 #undef FORMAT
02753 #undef FORMAT2
02754 }

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

Definition at line 2876 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, h, NULL, dundi_precache_queue::number, and ast_cli_entry::usage.

02877 {
02878 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02879 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02880    struct dundi_precache_queue *qe;
02881    int h,m,s;
02882    time_t now;
02883    switch (cmd) {
02884    case CLI_INIT:
02885       e->command = "dundi show precache";
02886       e->usage =
02887          "Usage: dundi show precache\n"
02888          "       Lists all known DUNDi scheduled precache updates.\n";
02889       return NULL;
02890    case CLI_GENERATE:
02891       return NULL;
02892    }
02893    if (a->argc != 3) {
02894       return CLI_SHOWUSAGE;
02895    }
02896    time(&now);
02897    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
02898    AST_LIST_LOCK(&pcq);
02899    AST_LIST_TRAVERSE(&pcq, qe, list) {
02900       s = qe->expiration - now;
02901       h = s / 3600;
02902       s = s % 3600;
02903       m = s / 60;
02904       s = s % 60;
02905       ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
02906    }
02907    AST_LIST_UNLOCK(&pcq);
02908 
02909    return CLI_SUCCESS;
02910 #undef FORMAT
02911 #undef FORMAT2
02912 }

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

Definition at line 2809 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, NULL, dundi_request::number, dundi_request::respcount, dundi_request::root_eid, and ast_cli_entry::usage.

02810 {
02811 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02812 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02813    struct dundi_request *req;
02814    char eidstr[20];
02815    switch (cmd) {
02816    case CLI_INIT:
02817       e->command = "dundi show requests";
02818       e->usage =
02819          "Usage: dundi show requests\n"
02820          "       Lists all known pending DUNDi requests.\n";
02821       return NULL;
02822    case CLI_GENERATE:
02823       return NULL;
02824    }
02825    if (a->argc != 3) {
02826       return CLI_SHOWUSAGE;
02827    }
02828    AST_LIST_LOCK(&peers);
02829    ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02830    AST_LIST_TRAVERSE(&requests, req, list) {
02831       ast_cli(a->fd, FORMAT, req->number, req->dcontext,
02832          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02833    }
02834    AST_LIST_UNLOCK(&peers);
02835    return CLI_SUCCESS;
02836 #undef FORMAT
02837 #undef FORMAT2
02838 }

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

Definition at line 2756 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, NULL, dundi_transaction::oseqno, dundi_transaction::strans, and ast_cli_entry::usage.

02757 {
02758 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02759 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02760    struct dundi_transaction *trans;
02761    switch (cmd) {
02762    case CLI_INIT:
02763       e->command = "dundi show trans";
02764       e->usage =
02765          "Usage: dundi show trans\n"
02766          "       Lists all known DUNDi transactions.\n";
02767       return NULL;
02768    case CLI_GENERATE:
02769       return NULL;
02770    }
02771    if (a->argc != 3) {
02772       return CLI_SHOWUSAGE;
02773    }
02774    AST_LIST_LOCK(&peers);
02775    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02776    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02777       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),
02778          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02779    }
02780    AST_LIST_UNLOCK(&peers);
02781    return CLI_SUCCESS;
02782 #undef FORMAT
02783 #undef FORMAT2
02784 }

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

Definition at line 2311 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, NULL, and ast_cli_entry::usage.

02312 {
02313    switch (cmd) {
02314    case CLI_INIT:
02315       e->command = "dundi store history {on|off}";
02316       e->usage =
02317          "Usage: dundi store history {on|off}\n"
02318          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02319          "purposes\n";
02320       return NULL;
02321    case CLI_GENERATE:
02322       return NULL;
02323    }
02324 
02325    if (a->argc != e->args) {
02326       return CLI_SHOWUSAGE;
02327    }
02328    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02329       global_storehistory = 1;
02330       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02331    } else {
02332       global_storehistory = 0;
02333       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02334    }
02335    return CLI_SUCCESS;
02336 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

Definition at line 3123 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().

03124 {
03125    int res;
03126    if (dundidebug)
03127       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
03128    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
03129    if (res < 0) {
03130       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",
03131          ast_inet_ntoa(pack->parent->addr.sin_addr),
03132          ntohs(pack->parent->addr.sin_port), strerror(errno));
03133    }
03134    if (res > 0)
03135       res = 0;
03136    return res;
03137 }

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

Definition at line 4082 of file pbx_dundi.c.

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

04083 {
04084    int results;
04085    int x;
04086    struct dundi_result dr[MAX_RESULTS];
04087    AST_DECLARE_APP_ARGS(args,
04088       AST_APP_ARG(number);
04089       AST_APP_ARG(context);
04090       AST_APP_ARG(options);
04091    );
04092    char *parse;
04093    struct ast_flags opts = { 0, };
04094 
04095    buf[0] = '\0';
04096 
04097    if (ast_strlen_zero(num)) {
04098       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
04099       return -1;
04100    }
04101 
04102    parse = ast_strdupa(num);
04103 
04104    AST_STANDARD_APP_ARGS(args, parse);
04105 
04106    if (!ast_strlen_zero(args.options)) {
04107       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
04108    }
04109    if (ast_strlen_zero(args.context)) {
04110       args.context = "e164";
04111    }
04112 
04113    results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04114    if (results > 0) {
04115       sort_results(dr, results);
04116       for (x = 0; x < results; x++) {
04117          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
04118             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
04119             break;
04120          }
04121       }
04122    }
04123 
04124    return 0;
04125 }

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

Definition at line 1367 of file pbx_dundi.c.

References ast_aes_encrypt().

Referenced by dundi_encrypt().

01368 {
01369    unsigned char curblock[16];
01370    int x;
01371    memcpy(curblock, iv, sizeof(curblock));
01372    while(len > 0) {
01373       for (x=0;x<16;x++)
01374          curblock[x] ^= src[x];
01375       ast_aes_encrypt(curblock, dst, ecx);
01376       memcpy(curblock, dst, sizeof(curblock));
01377       dst += 16;
01378       src += 16;
01379       len -= 16;
01380    }
01381    return 0;
01382 }

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

Definition at line 513 of file pbx_dundi.c.

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

00514 {
00515    struct dundi_peer *cur = NULL;
00516 
00517    if (!eid)
00518       eid = &empty_eid;
00519 
00520    AST_LIST_TRAVERSE(&peers, cur, list) {
00521       if (!ast_eid_cmp(&cur->eid,eid))
00522          break;
00523    }
00524 
00525    if (!cur && any_peer)
00526       cur = any_peer;
00527 
00528    return cur;
00529 }

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

Definition at line 411 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(), NULL, 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().

00412 {
00413    struct dundi_transaction *trans;
00414 
00415    /* Look for an exact match first */
00416    AST_LIST_TRAVERSE(&alltrans, trans, all) {
00417       if (!inaddrcmp(&trans->addr, sin) &&
00418            ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
00419            ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
00420            if (hdr->strans)
00421               trans->dtrans = ntohs(hdr->strans) & 32767;
00422            return trans;
00423       }
00424    }
00425 
00426    switch(hdr->cmdresp & 0x7f) {
00427    case DUNDI_COMMAND_DPDISCOVER:
00428    case DUNDI_COMMAND_EIDQUERY:
00429    case DUNDI_COMMAND_PRECACHERQ:
00430    case DUNDI_COMMAND_REGREQ:
00431    case DUNDI_COMMAND_NULL:
00432    case DUNDI_COMMAND_ENCRYPT:
00433       if (!hdr->strans)
00434          break;
00435       /* Create new transaction */
00436       if (!(trans = create_transaction(NULL)))
00437          break;
00438       memcpy(&trans->addr, sin, sizeof(trans->addr));
00439       trans->dtrans = ntohs(hdr->strans) & 32767;
00440    default:
00441       break;
00442    }
00443 
00444    return trans;
00445 }

static int get_mapping_weight ( struct dundi_mapping map,
struct varshead headp 
) [static]

Definition at line 557 of file pbx_dundi.c.

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

Referenced by dundi_lookup_local(), and dundi_show_mappings().

00558 {
00559    char buf[32];
00560 
00561    buf[0] = 0;
00562    if (map->weightstr) {
00563       if (headp) {
00564          pbx_substitute_variables_varshead(headp, map->weightstr, buf, sizeof(buf) - 1);
00565       } else {                
00566          pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
00567       }
00568 
00569       if (sscanf(buf, "%30d", &map->_weight) != 1)
00570          map->_weight = MAX_WEIGHT;
00571    }
00572 
00573    return map->_weight;
00574 }

static int get_trans_id ( void   )  [static]

Definition at line 478 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

00479 {
00480    struct dundi_transaction *t;
00481    int stid = (ast_random() % 32766) + 1;
00482    int tid = stid;
00483 
00484    do {
00485       AST_LIST_TRAVERSE(&alltrans, t, all) {
00486          if (t->strans == tid)
00487             break;
00488       }
00489       if (!t)
00490          return tid;
00491       tid = (tid % 32766) + 1;
00492    } while (tid != stid);
00493 
00494    return 0;
00495 }

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

Definition at line 1569 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_alloca, 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, NULL, 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, retval, 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().

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