Thu Jul 9 13:41:27 2009

Asterisk developer's documentation


pbx_dundi.c File Reference

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

#include "asterisk.h"
#include "asterisk/network.h"
#include <sys/ioctl.h>
#include <zlib.h>
#include <sys/signal.h>
#include <pthread.h>
#include <net/if.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/md5.h"
#include "asterisk/dundi.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
#include "asterisk/netsock.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/aes.h"
#include "asterisk/app.h"
#include "dundi-parser.h"

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void abort_request (struct dundi_request *dr)
static int ack_trans (struct dundi_transaction *trans, int iseqno)
static void append_permission (struct permissionlist *permlist, const char *s, int allow)
static int append_transaction (struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
static void apply_peer (struct dundi_transaction *trans, struct dundi_peer *p)
static unsigned long avoid_crc32 (dundi_eid *avoid[])
static void build_iv (unsigned char *iv)
static void build_mapping (const char *name, const char *value)
static void build_peer (dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
static void build_secret (char *secret, int seclen)
static void build_transactions (struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
static int cache_lookup (struct dundi_request *req, dundi_eid *peer_eid, uint32_t crc32, int *lowexpiration)
static int cache_lookup_internal (time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
static int cache_save (dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
static int cache_save_hint (dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
static void cancel_request (struct dundi_request *dr)
static int check_key (struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, uint32_t keycrc32)
static void check_password (void)
static int check_request (struct dundi_request *dr)
static char * complete_peer_helper (const char *line, const char *word, int pos, int state, int rpos)
static struct dundi_transactioncreate_transaction (struct dundi_peer *p)
static int decrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_decrypt_key *dcx)
static void deep_copy_peer (struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
static void destroy_map (struct dundi_mapping *map)
static void destroy_packet (struct dundi_packet *pack, int needfree)
static void destroy_packets (struct packetlist *p)
static void destroy_peer (struct dundi_peer *peer)
static void destroy_permissions (struct permissionlist *permlist)
static void destroy_trans (struct dundi_transaction *trans, int fromtimeout)
static int discover_transactions (struct dundi_request *dr)
static int do_autokill (const void *data)
static int do_qualify (const void *data)
static int do_register (const void *data)
static int do_register_expire (const void *data)
static void drds_destroy (struct dundi_result_datastore *drds)
static void drds_destroy_cb (void *data)
static int dundi_ack (struct dundi_transaction *trans, int final)
static int dundi_answer_entity (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_answer_query (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static void dundi_debug_output (const char *data)
static struct dundi_hdrdundi_decrypt (struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
static int dundi_discover (struct dundi_transaction *trans)
static char * dundi_do_debug_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 char * dundi_do_store_history_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dundi_encrypt (struct dundi_transaction *trans, struct dundi_packet *pack)
static void dundi_error_output (const char *data)
static int dundi_exec (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static char * dundi_flush (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dundi_helper (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag)
static void dundi_ie_append_eid_appropriately (struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us)
int dundi_lookup (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass)
 Lookup the given number in the given dundi context. Lookup number in a given dundi context (if unspecified use e164), the given callerid (if specified) and return up to maxret results in the array specified.
static int dundi_lookup_internal (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[])
static int dundi_lookup_local (struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
static void * dundi_lookup_thread (void *data)
static int dundi_matchmore (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
int dundi_precache (const char *context, const char *number)
 Pre-cache to push upstream peers.
static void dundi_precache_full (void)
static int dundi_precache_internal (const char *context, const char *number, int ttl, dundi_eid *avoids[])
static void * dundi_precache_thread (void *data)
static int dundi_prop_precache (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_query (struct dundi_transaction *trans)
int dundi_query_eid (struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid)
 Retrieve information on a specific EID.
static int dundi_query_eid_internal (struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[])
static int dundi_query_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static void * dundi_query_thread (void *data)
static void dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin)
static int dundi_result_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int dundi_rexmit (const void *data)
static int dundi_send (struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
static char * dundi_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_entityid (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_mappings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_peer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_peers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_precache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_requests (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_show_trans (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * dundi_store_history (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int dundi_xmit (struct dundi_packet *pack)
static int dundifunc_read (struct ast_channel *chan, const char *cmd, char *num, char *buf, size_t len)
static int encrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_encrypt_key *ecx)
static struct dundi_peerfind_peer (dundi_eid *eid)
static struct dundi_transactionfind_transaction (struct dundi_hdr *hdr, struct sockaddr_in *sin)
static int get_mapping_weight (struct dundi_mapping *map)
static int get_trans_id (void)
static int handle_command_response (struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
static int handle_frame (struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)
static int has_permission (struct permissionlist *permlist, char *cont)
static int load_module (void)
static void load_password (void)
static void mark_mappings (void)
static void mark_peers (void)
static char * model2str (int model)
static void * network_thread (void *ignore)
static int optimize_transactions (struct dundi_request *dr, int order)
static void populate_addr (struct dundi_peer *peer, dundi_eid *eid)
static int precache_trans (struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
static int precache_transactions (struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
static void * process_clearcache (void *ignore)
static void * process_precache (void *ign)
static void prune_mappings (void)
static void prune_peers (void)
static void qualify_peer (struct dundi_peer *peer, int schedonly)
static int query_transactions (struct dundi_request *dr)
static int register_request (struct dundi_request *dr, struct dundi_request **pending)
static int reload (void)
static void reschedule_precache (const char *number, const char *context, int expiration)
static int rescomp (const void *a, const void *b)
static void reset_global_eid (void)
static int reset_transaction (struct dundi_transaction *trans)
static void save_secret (const char *newkey, const char *oldkey)
static int set_config (char *config_file, struct sockaddr_in *sin, 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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct dundi_peerany_peer
 Wildcard peer.
static const 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 struct ast_cli_entry cli_dundi_do_debug_deprecated = { .handler = dundi_do_debug_deprecated , .summary = "Enable/Disable DUNDi debugging" ,__VA_ARGS__ }
static struct ast_cli_entry cli_dundi_do_store_history_deprecated = { .handler = dundi_do_store_history_deprecated , .summary = "Enable/Disable DUNDi historic records" ,__VA_ARGS__ }
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
unsigned int dundi_result_id
static int dundi_shutdown = 0
static struct ast_switch dundi_switch
static int dundi_ttl = DUNDI_DEFAULT_TTL
static int dundidebug = 0
static char email [80]
static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }
static int global_autokilltimeout = 0
static dundi_eid global_eid
static int global_storehistory = 0
static struct io_contextio
static char ipaddr [80]
static char locality [80]
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char org [80]
static char phone [80]
static pthread_t precachethreadid = AST_PTHREADT_NULL
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static char stateprov [80]
static unsigned int tos = 0


Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 91 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 74 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 75 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 76 of file pbx_dundi.c.

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 96 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10

Keep times of last 10 lookups

Definition at line 79 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

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

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

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

#define MAX_OPTS   128

Definition at line 4256 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 70 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

Definition at line 68 of file pbx_dundi.c.

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

#define MAX_WEIGHT   59999

Definition at line 72 of file pbx_dundi.c.

Referenced by build_mapping(), and get_mapping_weight().


Enumeration Type Documentation

anonymous enum

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

Definition at line 81 of file pbx_dundi.c.

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

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3967 of file pbx_dundi.c.

03967      {
03968    OPT_BYPASS_CACHE = (1 << 0),
03969 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4921 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4921 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3458 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03459 {
03460    struct dundi_transaction *trans;
03461 
03462    AST_LIST_LOCK(&peers);
03463    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03464       /* This will remove the transaction from the list */
03465       destroy_trans(trans, 0);
03466    }
03467    AST_LIST_UNLOCK(&peers);
03468 }

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

Definition at line 1960 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, dundi_packet::list, LOG_WARNING, dundi_hdr::oseqno, dundi_transaction::packets, and sched.

Referenced by handle_frame().

01961 {
01962    struct dundi_packet *pack;
01963 
01964    /* Ack transmitted packet corresponding to iseqno */
01965    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01966       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01967          destroy_packet(pack, 0);
01968          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01969             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01970             destroy_packets(&trans->lasttrans);
01971          }
01972          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01973          AST_SCHED_DEL(sched, trans->autokillid);
01974          return 1;
01975       }
01976    }
01977 
01978    return 0;
01979 }

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

Definition at line 4243 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

04244 {
04245    struct permission *perm;
04246 
04247    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04248       return;
04249 
04250    strcpy(perm->name, s);
04251    perm->allow = allow;
04252 
04253    AST_LIST_INSERT_TAIL(permlist, perm, list);
04254 }

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

Definition at line 3413 of file pbx_dundi.c.

References dundi_peer::addr, ast_debug, AST_LIST_INSERT_HEAD, ast_strlen_zero(), create_transaction(), dr, dundi_eid_to_str(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, dundi_peer::maxms, dundi_transaction::parent, dundi_transaction::parentlist, and dundi_transaction::ttl.

Referenced by build_transactions().

03414 {
03415    struct dundi_transaction *trans;
03416    int x;
03417    char eid_str[20];
03418    char eid_str2[20];
03419 
03420    /* Ignore if not registered */
03421    if (!p->addr.sin_addr.s_addr)
03422       return 0;
03423    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03424       return 0;
03425 
03426    if (ast_strlen_zero(dr->number))
03427       ast_debug(1, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
03428    else
03429       ast_debug(1, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
03430 
03431    trans = create_transaction(p);
03432    if (!trans)
03433       return -1;
03434    trans->parent = dr;
03435    trans->ttl = ttl;
03436    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03437       trans->eids[x] = *avoid[x];
03438    trans->eidcount = x;
03439    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03440    
03441    return 0;
03442 }

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

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

01240 {
01241    if (!trans->addr.sin_addr.s_addr)
01242       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01243    trans->us_eid = p->us_eid;
01244    trans->them_eid = p->eid;
01245    /* Enable encryption if appropriate */
01246    if (!ast_strlen_zero(p->inkey))
01247       ast_set_flag(trans, FLAG_ENCRYPT);  
01248    if (p->maxms) {
01249       trans->autokilltimeout = p->maxms;
01250       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01251       if (p->lastms > 1) {
01252          trans->retranstimer = p->lastms * 2;
01253          /* Keep it from being silly */
01254          if (trans->retranstimer < 150)
01255             trans->retranstimer = 150;
01256       }
01257       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01258          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01259    } else
01260       trans->autokilltimeout = global_autokilltimeout;
01261 }

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

Definition at line 3579 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03580 {
03581    /* Idea is that we're calculating a checksum which is independent of
03582       the order that the EID's are listed in */
03583    uint32_t acrc32 = 0;
03584    int x;
03585    for (x=0;avoid[x];x++) {
03586       /* Order doesn't matter */
03587       if (avoid[x+1]) {
03588          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03589       }
03590    }
03591    return acrc32;
03592 }

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

Definition at line 489 of file pbx_dundi.c.

References ast_random().

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

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

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

Definition at line 4258 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdup, ast_strdupa, ast_strlen_zero(), DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, dundi_mapping::list, LOG_WARNING, map, MAX_OPTS, MAX_WEIGHT, and str2tech().

Referenced by set_config().

04259 {
04260    char *t, *fields[MAX_OPTS];
04261    struct dundi_mapping *map;
04262    int x;
04263    int y;
04264 
04265    t = ast_strdupa(value);
04266       
04267    AST_LIST_TRAVERSE(&mappings, map, list) {
04268       /* Find a double match */
04269       if (!strcasecmp(map->dcontext, name) && 
04270          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
04271            (!value[strlen(map->lcontext)] || 
04272             (value[strlen(map->lcontext)] == ','))))
04273          break;
04274    }
04275    if (!map) {
04276       if (!(map = ast_calloc(1, sizeof(*map))))
04277          return;
04278       AST_LIST_INSERT_HEAD(&mappings, map, list);
04279       map->dead = 1;
04280    }
04281    map->options = 0;
04282    memset(fields, 0, sizeof(fields));
04283    x = 0;
04284    while (t && x < MAX_OPTS) {
04285       fields[x++] = t;
04286       t = strchr(t, ',');
04287       if (t) {
04288          *t = '\0';
04289          t++;
04290       }
04291    } /* Russell was here, arrrr! */
04292    if ((x == 1) && ast_strlen_zero(fields[0])) {
04293       /* Placeholder mapping */
04294       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04295       map->dead = 0;
04296    } else if (x >= 4) {
04297       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04298       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04299       if ((sscanf(fields[1], "%d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) {
04300          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04301          if ((map->tech = str2tech(fields[2])))
04302             map->dead = 0;
04303       } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') {
04304          map->weightstr = ast_strdup(fields[1]);
04305          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04306          if ((map->tech = str2tech(fields[2])))
04307             map->dead = 0;
04308       } else {
04309          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04310       }
04311       for (y = 4;y < x; y++) {
04312          if (!strcasecmp(fields[y], "nounsolicited"))
04313             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04314          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04315             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04316          else if (!strcasecmp(fields[y], "residential"))
04317             map->options |= DUNDI_FLAG_RESIDENTIAL;
04318          else if (!strcasecmp(fields[y], "commercial"))
04319             map->options |= DUNDI_FLAG_COMMERCIAL;
04320          else if (!strcasecmp(fields[y], "mobile"))
04321             map->options |= DUNDI_FLAG_MOBILE;
04322          else if (!strcasecmp(fields[y], "nopartial"))
04323             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04324          else
04325             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04326       }
04327    } else 
04328       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04329 }

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

Definition at line 4413 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_SCHED_DEL, dundi_peer::dead, destroy_permissions(), dundi_eid_cmp(), DUNDI_PORT, dundi_peer::eid, global_eid, hp, dundi_peer::include, dundi_peer::inkey, ast_variable::name, ast_variable::next, dundi_peer::outkey, dundi_peer::permit, populate_addr(), dundi_peer::registerid, sched, dundi_peer::us_eid, and ast_variable::value.

04414 {
04415    struct dundi_peer *peer;
04416    struct ast_hostent he;
04417    struct hostent *hp;
04418    dundi_eid testeid;
04419    int needregister=0;
04420    char eid_str[20];
04421 
04422    AST_LIST_LOCK(&peers);
04423    AST_LIST_TRAVERSE(&peers, peer, list) {
04424       if (!dundi_eid_cmp(&peer->eid, eid)) { 
04425          break;
04426       }
04427    }
04428    if (!peer) {
04429       /* Add us into the list */
04430       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04431          AST_LIST_UNLOCK(&peers);
04432          return;
04433       }
04434       peer->registerid = -1;
04435       peer->registerexpire = -1;
04436       peer->qualifyid = -1;
04437       peer->addr.sin_family = AF_INET;
04438       peer->addr.sin_port = htons(DUNDI_PORT);
04439       populate_addr(peer, eid);
04440       AST_LIST_INSERT_HEAD(&peers, peer, list);
04441    }
04442    peer->dead = 0;
04443    peer->eid = *eid;
04444    peer->us_eid = global_eid;
04445    destroy_permissions(&peer->permit);
04446    destroy_permissions(&peer->include);
04447    AST_SCHED_DEL(sched, peer->registerid);
04448    for (; v; v = v->next) {
04449       if (!strcasecmp(v->name, "inkey")) {
04450          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04451       } else if (!strcasecmp(v->name, "outkey")) {
04452          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04453       } else if (!strcasecmp(v->name, "host")) {
04454          if (!strcasecmp(v->value, "dynamic")) {
04455             peer->dynamic = 1;
04456          } else {
04457             hp = ast_gethostbyname(v->value, &he);
04458             if (hp) {
04459                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04460                peer->dynamic = 0;
04461             } else {
04462                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04463                peer->dead = 1;
04464             }
04465          }
04466       } else if (!strcasecmp(v->name, "ustothem")) {
04467          if (!dundi_str_to_eid(&testeid, v->value))
04468             peer->us_eid = testeid;
04469          else
04470             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04471       } else if (!strcasecmp(v->name, "include")) {
04472          append_permission(&peer->include, v->value, 1);
04473       } else if (!strcasecmp(v->name, "permit")) {
04474          append_permission(&peer->permit, v->value, 1);
04475       } else if (!strcasecmp(v->name, "noinclude")) {
04476          append_permission(&peer->include, v->value, 0);
04477       } else if (!strcasecmp(v->name, "deny")) {
04478          append_permission(&peer->permit, v->value, 0);
04479       } else if (!strcasecmp(v->name, "register")) {
04480          needregister = ast_true(v->value);
04481       } else if (!strcasecmp(v->name, "order")) {
04482          if (!strcasecmp(v->value, "primary"))
04483             peer->order = 0;
04484          else if (!strcasecmp(v->value, "secondary"))
04485             peer->order = 1;
04486          else if (!strcasecmp(v->value, "tertiary"))
04487             peer->order = 2;
04488          else if (!strcasecmp(v->value, "quartiary"))
04489             peer->order = 3;
04490          else {
04491             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);
04492          }
04493       } else if (!strcasecmp(v->name, "qualify")) {
04494          if (!strcasecmp(v->value, "no")) {
04495             peer->maxms = 0;
04496          } else if (!strcasecmp(v->value, "yes")) {
04497             peer->maxms = DEFAULT_MAXMS;
04498          } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
04499             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04500                dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04501             peer->maxms = 0;
04502          }
04503       } else if (!strcasecmp(v->name, "model")) {
04504          if (!strcasecmp(v->value, "inbound"))
04505             peer->model = DUNDI_MODEL_INBOUND;
04506          else if (!strcasecmp(v->value, "outbound")) 
04507             peer->model = DUNDI_MODEL_OUTBOUND;
04508          else if (!strcasecmp(v->value, "symmetric"))
04509             peer->model = DUNDI_MODEL_SYMMETRIC;
04510          else if (!strcasecmp(v->value, "none"))
04511             peer->model = 0;
04512          else {
04513             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04514                v->value, v->lineno);
04515          }
04516       } else if (!strcasecmp(v->name, "precache")) {
04517          if (!strcasecmp(v->value, "inbound"))
04518             peer->pcmodel = DUNDI_MODEL_INBOUND;
04519          else if (!strcasecmp(v->value, "outbound")) 
04520             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04521          else if (!strcasecmp(v->value, "symmetric"))
04522             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04523          else if (!strcasecmp(v->value, "none"))
04524             peer->pcmodel = 0;
04525          else {
04526             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04527                v->value, v->lineno);
04528          }
04529       }
04530    }
04531    (*globalpcmode) |= peer->pcmodel;
04532    if (!peer->model && !peer->pcmodel) {
04533       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04534          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04535       peer->dead = 1;
04536    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04537       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04538          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04539       peer->dead = 1;
04540    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04541       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04542          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04543       peer->dead = 1;
04544    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04545       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04546          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04547    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04548       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", 
04549          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04550    } else { 
04551       if (needregister) {
04552          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04553       }
04554       qualify_peer(peer, 1);
04555    }
04556    AST_LIST_UNLOCK(&peers);
04557 }

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

Definition at line 2050 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02051 {
02052    unsigned char tmp[16];
02053    char *s;
02054    build_iv(tmp);
02055    secret[0] = '\0';
02056    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02057    /* Eliminate potential bad characters */
02058    while((s = strchr(secret, ';'))) *s = '+';
02059    while((s = strchr(secret, '/'))) *s = '+';
02060    while((s = strchr(secret, ':'))) *s = '+';
02061    while((s = strchr(secret, '@'))) *s = '+';
02062 }

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

References append_transaction(), ast_clear_flag_nonstd, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, cache_lookup(), dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, has_permission(), dundi_peer::include, dundi_peer::list, 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().

03471 {
03472    struct dundi_peer *p;
03473    int x;
03474    int res;
03475    int pass;
03476    int allowconnect;
03477    char eid_str[20];
03478    AST_LIST_LOCK(&peers);
03479    AST_LIST_TRAVERSE(&peers, p, list) {
03480       if (modeselect == 1) {
03481          /* Send the precache to push upstreams only! */
03482          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03483          allowconnect = 1;
03484       } else {
03485          /* Normal lookup / EID query */
03486          pass = has_permission(&p->include, dr->dcontext);
03487          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03488       }
03489       if (skip) {
03490          if (!dundi_eid_cmp(skip, &p->eid))
03491             pass = 0;
03492       }
03493       if (pass) {
03494          if (p->order <= order) {
03495             /* Check order first, then check cache, regardless of
03496                omissions, this gets us more likely to not have an
03497                affected answer. */
03498             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03499                res = 0;
03500                /* Make sure we haven't already seen it and that it won't
03501                   affect our answer */
03502                for (x=0;avoid[x];x++) {
03503                   if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
03504                      /* If not a direct connection, it affects our answer */
03505                      if (directs && !directs[x]) 
03506                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03507                      break;
03508                   }
03509                }
03510                /* Make sure we can ask */
03511                if (allowconnect) {
03512                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03513                      /* Check for a matching or 0 cache entry */
03514                      append_transaction(dr, p, ttl, avoid);
03515                   } else {
03516                      ast_debug(1, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03517                   }
03518                }
03519             }
03520             *foundcache |= res;
03521          } else if (!*skipped || (p->order < *skipped))
03522             *skipped = p->order;
03523       }
03524    }
03525    AST_LIST_UNLOCK(&peers);
03526 }

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

Definition at line 1187 of file pbx_dundi.c.

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

Referenced by build_transactions().

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

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

Definition at line 1115 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_FLAGS_ALL, ast_get_time_t(), dundi_result::dest, dundi_request::dr, dundi_eid_to_str(), dundi_flags2str(), DUNDI_HINT_DONT_ASK, dundi_str_short_to_eid(), ast_flags::flags, dundi_request::hmd, dundi_request::respcount, dundi_mapping::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by cache_lookup().

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

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

Definition at line 844 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 809 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3444 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, dr, DUNDI_COMMAND_CANCEL, dundi_send(), dundi_transaction::parent, and dundi_transaction::parentlist.

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03445 {
03446    struct dundi_transaction *trans;
03447 
03448    AST_LIST_LOCK(&peers);
03449    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03450       /* Orphan transaction from request */
03451       trans->parent = NULL;
03452       /* Send final cancel */
03453       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03454    }
03455    AST_LIST_UNLOCK(&peers);
03456 }

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

Definition at line 1438 of file pbx_dundi.c.

References ast_aes_decrypt_key, ast_aes_encrypt_key, ast_check_signature_bin, ast_debug, ast_decrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_eid_to_str(), 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.

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

static void check_password ( void   )  [static]

Definition at line 2117 of file pbx_dundi.c.

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

Referenced by network_thread().

02118 {
02119    char oldsecret[80];
02120    time_t now;
02121    
02122    time(&now); 
02123 #if 0
02124    printf("%ld/%ld\n", now, rotatetime);
02125 #endif
02126    if ((now - rotatetime) >= 0) {
02127       /* Time to rotate keys */
02128       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02129       build_secret(cursecret, sizeof(cursecret));
02130       save_secret(cursecret, oldsecret);
02131    }
02132 }

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3565 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, and dundi_request::list.

Referenced by dundi_lookup_internal().

03566 {
03567    struct dundi_request *cur;
03568 
03569    AST_LIST_LOCK(&peers);
03570    AST_LIST_TRAVERSE(&requests, cur, list) {
03571       if (cur == dr)
03572          break;
03573    }
03574    AST_LIST_UNLOCK(&peers);
03575    
03576    return cur ? 1 : 0;
03577 }

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

Definition at line 2401 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

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

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

Definition at line 2920 of file pbx_dundi.c.

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

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

02921 {
02922    struct dundi_transaction *trans;
02923    int tid;
02924    
02925    /* Don't allow creation of transactions to non-registered peers */
02926    if (p && !p->addr.sin_addr.s_addr)
02927       return NULL;
02928    tid = get_trans_id();
02929    if (tid < 1)
02930       return NULL;
02931    if (!(trans = ast_calloc(1, sizeof(*trans))))
02932       return NULL;
02933 
02934    if (global_storehistory) {
02935       trans->start = ast_tvnow();
02936       ast_set_flag(trans, FLAG_STOREHIST);
02937    }
02938    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02939    trans->autokillid = -1;
02940    if (p) {
02941       apply_peer(trans, p);
02942       if (!p->sentfullkey)
02943          ast_set_flag(trans, FLAG_SENDFULLKEY);
02944    }
02945    trans->strans = tid;
02946    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02947    
02948    return trans;
02949 }

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

Definition at line 1330 of file pbx_dundi.c.

References ast_aes_decrypt.

Referenced by dundi_decrypt().

01331 {
01332    unsigned char lastblock[16];
01333    int x;
01334    memcpy(lastblock, iv, sizeof(lastblock));
01335    while(len > 0) {
01336       ast_aes_decrypt(src, dst, dcx);
01337       for (x=0;x<16;x++)
01338          dst[x] ^= lastblock[x];
01339       memcpy(lastblock, src, sizeof(lastblock));
01340       dst += 16;
01341       src += 16;
01342       len -= 16;
01343    }
01344    return 0;
01345 }

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

Definition at line 1491 of file pbx_dundi.c.

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

Referenced by handle_command_response().

01492 {
01493    struct permission *cur, *perm;
01494 
01495    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01496    
01497    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01498    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01499 
01500    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01501       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01502          continue;
01503 
01504       perm->allow = cur->allow;
01505       strcpy(perm->name, cur->name);
01506 
01507       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01508    }
01509 
01510    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01511       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01512          continue;
01513 
01514       perm->allow = cur->allow;
01515       strcpy(perm->name, cur->name);
01516 
01517       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01518    }
01519 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4206 of file pbx_dundi.c.

References ast_free, and map.

Referenced by prune_mappings().

04207 {
04208    if (map->weightstr)
04209       ast_free(map->weightstr);
04210    ast_free(map);
04211 }

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

Definition at line 2967 of file pbx_dundi.c.

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

Referenced by ack_trans().

02968 {
02969    if (pack->parent)
02970       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02971    AST_SCHED_DEL(sched, pack->retransid);
02972    if (needfree)
02973       ast_free(pack);
02974 }

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

Definition at line 1949 of file pbx_dundi.c.

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

Referenced by ack_trans(), and handle_frame().

01950 {
01951    struct dundi_packet *pack;
01952    
01953    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01954       AST_SCHED_DEL(sched, pack->retransid);
01955       ast_free(pack);
01956    }
01957 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 4195 of file pbx_dundi.c.

References ast_free, AST_SCHED_DEL, destroy_permissions(), destroy_trans(), dundi_peer::include, dundi_peer::permit, dundi_peer::qualifyid, dundi_peer::registerid, dundi_peer::regtrans, and sched.

Referenced by prune_peers().

04196 {
04197    AST_SCHED_DEL(sched, peer->registerid);
04198    if (peer->regtrans)
04199       destroy_trans(peer->regtrans, 0);
04200    AST_SCHED_DEL(sched, peer->qualifyid);
04201    destroy_permissions(&peer->permit);
04202    destroy_permissions(&peer->include);
04203    ast_free(peer);
04204 }

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

Definition at line 4187 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, and permission::list.

Referenced by build_peer(), and destroy_peer().

04188 {
04189    struct permission *perm;
04190 
04191    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04192       ast_free(perm);
04193 }

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

Definition at line 2976 of file pbx_dundi.c.

References ast_free, AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), dundi_peer::avgms, dundi_request::dcontext, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, dundi_peer::lastms, dundi_peer::list, LOG_NOTICE, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::maxms, dundi_request::number, dundi_transaction::parent, dundi_peer::qualtrans, dundi_peer::qualtx, dundi_peer::regtrans, dundi_transaction::start, and dundi_transaction::them_eid.

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

02977 {
02978    struct dundi_peer *peer;
02979    int ms;
02980    int x;
02981    int cnt;
02982    char eid_str[20];
02983    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02984       AST_LIST_TRAVERSE(&peers, peer, list) {
02985          if (peer->regtrans == trans)
02986             peer->regtrans = NULL;
02987          if (peer->qualtrans == trans) {
02988             if (fromtimeout) {
02989                if (peer->lastms > -1)
02990                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02991                peer->lastms = -1;
02992             } else {
02993                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02994                if (ms < 1)
02995                   ms = 1;
02996                if (ms < peer->maxms) {
02997                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02998                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02999                } else if (peer->lastms < peer->maxms) {
03000                   ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
03001                }
03002                peer->lastms = ms;
03003             }
03004             peer->qualtrans = NULL;
03005          }
03006          if (ast_test_flag(trans, FLAG_STOREHIST)) {
03007             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
03008                if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
03009                   peer->avgms = 0;
03010                   cnt = 0;
03011                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
03012                      ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
03013                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
03014                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
03015                      peer->lookups[x] = peer->lookups[x-1];
03016                      if (peer->lookups[x]) {
03017                         peer->avgms += peer->lookuptimes[x];
03018                         cnt++;
03019                      }
03020                   }
03021                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
03022                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
03023                   if (peer->lookups[0]) {
03024                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
03025                      peer->avgms += peer->lookuptimes[0];
03026                      cnt++;
03027                   }
03028                   if (cnt)
03029                      peer->avgms /= cnt;
03030                }
03031             }
03032          }
03033       }
03034    }
03035    if (trans->parent) {
03036       /* Unlink from parent if appropriate */
03037       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
03038       if (AST_LIST_EMPTY(&trans->parent->trans)) {
03039          /* Wake up sleeper */
03040          if (trans->parent->pfds[1] > -1) {
03041             if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
03042                ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
03043             }
03044          }
03045       }
03046    }
03047    /* Unlink from all trans */
03048    AST_LIST_REMOVE(&alltrans, trans, all);
03049    destroy_packets(&trans->packets);
03050    destroy_packets(&trans->lasttrans);
03051    AST_SCHED_DEL(sched, trans->autokillid);
03052    if (trans->thread) {
03053       /* If used by a thread, mark as dead and be done */
03054       ast_set_flag(trans, FLAG_DEAD);
03055    } else
03056       ast_free(trans);
03057 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3298 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, dundi_discover(), and dundi_transaction::parentlist.

Referenced by dundi_lookup_internal().

03299 {
03300    struct dundi_transaction *trans;
03301    AST_LIST_LOCK(&peers);
03302    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03303       dundi_discover(trans);
03304    }
03305    AST_LIST_UNLOCK(&peers);
03306    return 0;
03307 }

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

Definition at line 3153 of file pbx_dundi.c.

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

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

03154 {
03155    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03156    char eid_str[20];
03157    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03158       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03159    trans->autokillid = -1;
03160    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03161    return 0;
03162 }

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

Definition at line 4358 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04359 {
04360    struct dundi_peer *peer = (struct dundi_peer *)data;
04361    peer->qualifyid = -1;
04362    qualify_peer(peer, 0);
04363    return 0;
04364 }

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

Definition at line 4332 of file pbx_dundi.c.

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

04333 {
04334    struct dundi_ie_data ied;
04335    struct dundi_peer *peer = (struct dundi_peer *)data;
04336    char eid_str[20];
04337    char eid_str2[20];
04338    ast_debug(1, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
04339    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04340    /* Destroy old transaction if there is one */
04341    if (peer->regtrans)
04342       destroy_trans(peer->regtrans, 0);
04343    peer->regtrans = create_transaction(peer);
04344    if (peer->regtrans) {
04345       ast_set_flag(peer->regtrans, FLAG_ISREG);
04346       memset(&ied, 0, sizeof(ied));
04347       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04348       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04349       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04350       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04351       
04352    } else
04353       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04354 
04355    return 0;
04356 }

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

Note:
Called with the peers list already locked

Definition at line 1264 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

01265 {
01266    struct dundi_peer *peer = (struct dundi_peer *)data;
01267    char eid_str[20];
01268    ast_debug(1, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01269    peer->registerexpire = -1;
01270    peer->lastms = 0;
01271    memset(&peer->addr, 0, sizeof(peer->addr));
01272    return 0;
01273 }

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3983 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03984 {
03985    ast_free(drds);
03986 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3988 of file pbx_dundi.c.

References drds_destroy().

03989 {
03990    struct dundi_result_datastore *drds = data;
03991    drds_destroy(drds);
03992 }

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

Definition at line 363 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

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

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

Definition at line 754 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 1032 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

References chan, DUNDI_FLAG_CANMATCH, and dundi_helper().

04604 {
04605    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04606 }

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

Definition at line 270 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

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

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

Definition at line 1347 of file pbx_dundi.c.

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

01348 {
01349    int space = *dstlen;
01350    unsigned long bytes;
01351    struct dundi_hdr *h;
01352    unsigned char *decrypt_space;
01353    decrypt_space = alloca(srclen);
01354    if (!decrypt_space)
01355       return NULL;
01356    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01357    /* Setup header */
01358    h = (struct dundi_hdr *)dst;
01359    *h = *ohdr;
01360    bytes = space - 6;
01361    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01362       ast_debug(1, "Ouch, uncompress failed :(\n");
01363       return NULL;
01364    }
01365    /* Update length */
01366    *dstlen = bytes + 6;
01367    /* Return new header */
01368    return h;
01369 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3186 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, sched, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by discover_transactions().

03187 {
03188    struct dundi_ie_data ied;
03189    int x;
03190    if (!trans->parent) {
03191       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03192       return -1;
03193    }
03194    memset(&ied, 0, sizeof(ied));
03195    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03196    if (!dundi_eid_zero(&trans->us_eid))
03197       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03198    for (x=0;x<trans->eidcount;x++)
03199       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03200    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03201    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03202    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03203    if (trans->parent->cbypass)
03204       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03205    if (trans->autokilltimeout)
03206       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03207    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03208 }

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

Definition at line 2239 of file pbx_dundi.c.

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

02240 {
02241    switch (cmd) {
02242    case CLI_INIT:
02243       e->command = "dundi [no] debug";
02244       e->usage = 
02245          "Usage: dundi [no] debug\n"
02246          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02247       return NULL;
02248    case CLI_GENERATE:
02249       return NULL;
02250    }
02251    if (a->argc < 2 || a->argc > 3)
02252       return CLI_SHOWUSAGE;
02253    if (a->argc == 2) {
02254       dundidebug = 1;
02255       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02256    } else {
02257       dundidebug = 0;
02258       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02259    }
02260    return CLI_SUCCESS;
02261 }

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

Definition at line 2440 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, dr, dundi_flags2str(), dundi_lookup(), ast_cli_args::fd, MAX_RESULTS, sort_results(), and ast_cli_entry::usage.

02441 {
02442    int res;
02443    char tmp[256];
02444    char fs[80] = "";
02445    char *context;
02446    int x;
02447    int bypass = 0;
02448    struct dundi_result dr[MAX_RESULTS];
02449    struct timeval start;
02450    switch (cmd) {
02451    case CLI_INIT:
02452       e->command = "dundi lookup";
02453       e->usage =
02454          "Usage: dundi lookup <number>[@context] [bypass]\n"
02455          "       Lookup the given number within the given DUNDi context\n"
02456          "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
02457          "keyword is specified.\n";
02458       return NULL;
02459    case CLI_GENERATE:
02460       return NULL;
02461    }
02462 
02463    if ((a->argc < 3) || (a->argc > 4))
02464       return CLI_SHOWUSAGE;
02465    if (a->argc > 3) {
02466       if (!strcasecmp(a->argv[3], "bypass"))
02467          bypass=1;
02468       else
02469          return CLI_SHOWUSAGE;
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 %d 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, 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    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02515    context = strchr(tmp, '@');
02516    if (context) {
02517       *context = '\0';
02518       context++;
02519    }
02520    start = ast_tvnow();
02521    res = dundi_precache(context, tmp);
02522    
02523    if (res < 0) 
02524       ast_cli(a->fd, "DUNDi precache returned error.\n");
02525    else if (!res) 
02526       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02527    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02528    return CLI_SUCCESS;
02529 }

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

Definition at line 2531 of file pbx_dundi.c.

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

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

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

Definition at line 2289 of file pbx_dundi.c.

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

02290 {
02291    switch (cmd) {
02292    case CLI_INIT:
02293       e->command = "dundi [no] store history";
02294       e->usage = 
02295          "Usage: dundi [no] store history\n"
02296          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02297          "purposes\n";
02298       return NULL;
02299    case CLI_GENERATE:
02300       return NULL;
02301    }
02302    if (a->argc < 3 || a->argc > 4)
02303       return CLI_SHOWUSAGE;
02304    
02305    if (a->argc == 3) {
02306       global_storehistory = 1;
02307       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02308    } else {
02309       global_storehistory = 0;
02310       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02311    }
02312    return CLI_SUCCESS;
02313 }

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

Definition at line 1371 of file pbx_dundi.c.

References ast_debug, ast_log(), ast_set_flag, ast_test_flag, build_iv(), dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dcx, DUNDI_COMMAND_ENCRYPT, dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_int(), dundi_ie_append_raw(), DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_KEYCRC32, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, dundi_transaction::ecx, encrypt_memcpy(), find_peer(), FLAG_SENDFULLKEY, dundi_packet::h, dundi_hdr::ies, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_hdr::oseqno, dundi_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().

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

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

Definition at line 276 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

Definition at line 4608 of file pbx_dundi.c.

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

04609 {
04610    struct dundi_result results[MAX_RESULTS];
04611    int res;
04612    int x=0;
04613    char req[1024];
04614    const char *dundiargs;
04615    struct ast_app *dial;
04616    
04617    if (!strncasecmp(context, "macro-", 6)) {
04618       if (!chan) {   
04619          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04620          return -1;
04621       }
04622       /* If done as a macro, use macro extension */
04623       if (!strcasecmp(exten, "s")) {
04624          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04625          if (ast_strlen_zero(exten))
04626             exten = chan->macroexten;
04627          if (ast_strlen_zero(exten))
04628             exten = chan->exten;
04629          if (ast_strlen_zero(exten)) { 
04630             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04631             return -1;
04632          }
04633       }
04634       if (ast_strlen_zero(data))
04635          data = "e164";
04636    } else {
04637       if (ast_strlen_zero(data))
04638          data = context;
04639    }
04640    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04641    if (res > 0) {
04642       sort_results(results, res);
04643       for (x=0;x<res;x++) {
04644          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04645             if (!--priority)
04646                break;
04647          }
04648       }
04649    }
04650    if (x < res) {
04651       /* Got a hit! */
04652       dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
04653       snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest, 
04654          S_OR(dundiargs, ""));
04655       dial = pbx_findapp("Dial");
04656       if (dial)
04657          res = pbx_exec(chan, dial, req);
04658    } else
04659       res = -1;
04660    return res;
04661 }

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

References chan, DUNDI_FLAG_EXISTS, and dundi_helper().

04599 {
04600    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04601 }

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

Definition at line 2342 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::list, dundi_peer::lookups, dundi_peer::lookuptimes, and ast_cli_entry::usage.

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

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

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

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

04560 {
04561    struct dundi_result results[MAX_RESULTS];
04562    int res;
04563    int x;
04564    int found = 0;
04565    if (!strncasecmp(context, "macro-", 6)) {
04566       if (!chan) {   
04567          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04568          return -1;
04569       }
04570       /* If done as a macro, use macro extension */
04571       if (!strcasecmp(exten, "s")) {
04572          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04573          if (ast_strlen_zero(exten))
04574             exten = chan->macroexten;
04575          if (ast_strlen_zero(exten))
04576             exten = chan->exten;
04577          if (ast_strlen_zero(exten)) { 
04578             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04579             return -1;
04580          }
04581       }
04582       if (ast_strlen_zero(data))
04583          data = "e164";
04584    } else {
04585       if (ast_strlen_zero(data))
04586          data = context;
04587    }
04588    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04589    for (x=0;x<res;x++) {
04590       if (ast_test_flag(results + x, flag))
04591          found++;
04592    }
04593    if (found >= priority)
04594       return 1;
04595    return 0;
04596 }

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

Definition at line 3164 of file pbx_dundi.c.

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

Referenced by dundi_discover().

03165 {
03166    struct dundi_peer *p;
03167    if (!dundi_eid_cmp(eid, us)) {
03168       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03169       return;
03170    }
03171    AST_LIST_LOCK(&peers);
03172    AST_LIST_TRAVERSE(&peers, p, list) {
03173       if (!dundi_eid_cmp(&p->eid, eid)) {
03174          if (has_permission(&p->include, context))
03175             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03176          else
03177             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03178          break;
03179       }
03180    }
03181    if (!p)
03182       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03183    AST_LIST_UNLOCK(&peers);
03184 }

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

References chan, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, and dundi_lookup_internal().

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

03697 {
03698    struct dundi_hint_metadata hmd;
03699    dundi_eid *avoid[1] = { NULL, };
03700    int direct[1] = { 0, };
03701    int expiration = dundi_cache_time;
03702    memset(&hmd, 0, sizeof(hmd));
03703    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03704    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03705 }

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

References abort_request(), ast_check_hangup(), ast_copy_string(), ast_debug, AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), chan, check_request(), discover_transactions(), dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, LOG_WARNING, ast_channel::name, optimize_transactions(), register_request(), dundi_request::root_eid, and unregister_request().

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

03595 {
03596    int res;
03597    struct dundi_request dr, *pending;
03598    dundi_eid *rooteid=NULL;
03599    int x;
03600    int ttlms;
03601    int ms;
03602    int foundcache;
03603    int skipped=0;
03604    int order=0;
03605    char eid_str[20];
03606    struct timeval start;
03607    
03608    /* Don't do anthing for a hungup channel */
03609    if (chan && ast_check_hangup(chan))
03610       return 0;
03611 
03612    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03613 
03614    for (x=0;avoid[x];x++)
03615       rooteid = avoid[x];
03616    /* Now perform real check */
03617    memset(&dr, 0, sizeof(dr));
03618    if (pipe(dr.pfds)) {
03619       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03620       return -1;
03621    }
03622    dr.dr = result;
03623    dr.hmd = hmd;
03624    dr.maxcount = maxret;
03625    dr.expiration = *expiration;
03626    dr.cbypass = cbypass;
03627    dr.crc32 = avoid_crc32(avoid);
03628    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03629    ast_copy_string(dr.number, number, sizeof(dr.number));
03630    if (rooteid)
03631       dr.root_eid = *rooteid;
03632    res = register_request(&dr, &pending);
03633    if (res) {
03634       /* Already a request */
03635       if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03636          /* This is on behalf of someone else.  Go ahead and close this out since
03637             they'll get their answer anyway. */
03638          ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03639             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03640          close(dr.pfds[0]);
03641          close(dr.pfds[1]);
03642          return -2;
03643       } else {
03644          /* Wait for the cache to populate */
03645          ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n",
03646             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03647          start = ast_tvnow();
03648          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03649             /* XXX Would be nice to have a way to poll/select here XXX */
03650             /* XXX this is a busy wait loop!!! */
03651             usleep(1);
03652          }
03653          /* Continue on as normal, our cache should kick in */
03654       }
03655    }
03656    /* Create transactions */
03657    do {
03658       order = skipped;
03659       skipped = 0;
03660       foundcache = 0;
03661       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03662    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03663    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03664       do this earlier because we didn't know if we were going to have transactions
03665       or not. */
03666    if (!ttl) {
03667       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03668       abort_request(&dr);
03669       unregister_request(&dr);
03670       close(dr.pfds[0]);
03671       close(dr.pfds[1]);
03672       return 0;
03673    }
03674       
03675    /* Optimize transactions */
03676    optimize_transactions(&dr, order);
03677    /* Actually perform transactions */
03678    discover_transactions(&dr);
03679    /* Wait for transaction to come back */
03680    start = ast_tvnow();
03681    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03682       ms = 100;
03683       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03684    }
03685    if (chan && ast_check_hangup(chan))
03686       ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03687    cancel_request(&dr);
03688    unregister_request(&dr);
03689    res = dr.respcount;
03690    *expiration = dr.expiration;
03691    close(dr.pfds[0]);
03692    close(dr.pfds[1]);
03693    return res;
03694 }

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

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

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 602 of file pbx_dundi.c.

References ast_debug, 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, dr, DUNDI_CAUSE_DUPLICATE, DUNDI_COMMAND_DPRESPONSE, dundi_eid_to_str(), 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, FLAG_DEAD, dundi_query_state::maps, MAX_RESULTS, dundi_query_state::nocache, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_query().

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

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

References chan, DUNDI_FLAG_MATCHMORE, and dundi_helper().

04664 {
04665    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04666 }

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

Pre-cache to push upstream peers.

Definition at line 3840 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03841 {
03842    dundi_eid *avoid[1] = { NULL, };
03843    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03844 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3743 of file pbx_dundi.c.

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

Referenced by set_config().

03744 {
03745    struct dundi_mapping *cur;
03746    struct ast_context *con;
03747    struct ast_exten *e;
03748 
03749    AST_LIST_TRAVERSE(&mappings, cur, list) {
03750       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03751       ast_rdlock_contexts();
03752       con = NULL;
03753       while ((con = ast_walk_contexts(con))) {
03754          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03755             continue;
03756          /* Found the match, now queue them all up */
03757          ast_rdlock_context(con);
03758          e = NULL;
03759          while ((e = ast_walk_context_extensions(con, e)))
03760             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03761          ast_unlock_context(con);
03762       }
03763       ast_unlock_contexts();
03764    }
03765 }

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

Definition at line 3767 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, errno, dundi_mapping::list, LOG_NOTICE, LOG_WARNING, MAX_RESULTS, optimize_transactions(), precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

03768 {
03769    struct dundi_request dr;
03770    struct dundi_hint_metadata hmd;
03771    struct dundi_result dr2[MAX_RESULTS];
03772    struct timeval start;
03773    struct dundi_mapping *maps = NULL, *cur;
03774    int nummaps = 0;
03775    int foundanswers;
03776    int foundcache, skipped, ttlms, ms;
03777    if (!context)
03778       context = "e164";
03779    ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
03780 
03781    AST_LIST_LOCK(&peers);
03782    AST_LIST_TRAVERSE(&mappings, cur, list) {
03783       if (!strcasecmp(cur->dcontext, context))
03784          nummaps++;
03785    }
03786    if (nummaps) {
03787       maps = alloca(nummaps * sizeof(*maps));
03788       nummaps = 0;
03789       if (maps) {
03790          AST_LIST_TRAVERSE(&mappings, cur, list) {
03791             if (!strcasecmp(cur->dcontext, context))
03792                maps[nummaps++] = *cur;
03793          }
03794       }
03795    }
03796    AST_LIST_UNLOCK(&peers);
03797    if (!nummaps || !maps)
03798       return -1;
03799    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03800    memset(&dr2, 0, sizeof(dr2));
03801    memset(&dr, 0, sizeof(dr));
03802    memset(&hmd, 0, sizeof(hmd));
03803    dr.dr = dr2;
03804    ast_copy_string(dr.number, number, sizeof(dr.number));
03805    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03806    dr.maxcount = MAX_RESULTS;
03807    dr.expiration = dundi_cache_time;
03808    dr.hmd = &hmd;
03809    dr.pfds[0] = dr.pfds[1] = -1;
03810    if (pipe(dr.pfds) < 0) {
03811       ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno));
03812       return -1;
03813    }
03814    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03815    optimize_transactions(&dr, 0);
03816    foundanswers = 0;
03817    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03818    if (foundanswers) {
03819       if (dr.expiration > 0) 
03820          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03821       else
03822          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03823    }
03824    start = ast_tvnow();
03825    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03826       if (dr.pfds[0] > -1) {
03827          ms = 100;
03828          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03829       } else
03830          usleep(1);
03831    }
03832    cancel_request(&dr);
03833    if (dr.pfds[0] > -1) {
03834       close(dr.pfds[0]);
03835       close(dr.pfds[1]);
03836    }
03837    return 0;
03838 }

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

Definition at line 666 of file pbx_dundi.c.

References ast_debug, 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_eid_to_str(), DUNDI_HINT_DONT_ASK, dundi_precache_internal(), dundi_send(), dundi_query_state::eids, dundi_hint_metadata::exten, FLAG_DEAD, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

00667 {
00668    struct dundi_query_state *st = data;
00669    struct dundi_ie_data ied;
00670    struct dundi_hint_metadata hmd;
00671    char eid_str[20];
00672 
00673    ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00674       st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00675    memset(&ied, 0, sizeof(ied));
00676 
00677    /* Now produce precache */
00678    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00679 
00680    AST_LIST_LOCK(&peers);
00681    /* Truncate if "don't ask" isn't present */
00682    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00683       hmd.exten[0] = '\0';
00684    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00685       ast_debug(1, "Our transaction went away!\n");
00686       st->trans->thread = 0;
00687       destroy_trans(st->trans, 0);
00688    } else {
00689       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00690       st->trans->thread = 0;
00691    }
00692    AST_LIST_UNLOCK(&peers);
00693    ast_free(st);
00694    return NULL;   
00695 }

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

Definition at line 885 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_string(), dundi_result::dest, dundi_request::dr, dr, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_request::hmd, ies, MAX_RESULTS, dundi_request::maxcount, dundi_transaction::parent, dundi_request::respcount, s, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by handle_command_response().

00886 {
00887    struct dundi_query_state *st;
00888    int totallen;
00889    int x,z;
00890    struct dundi_ie_data ied;
00891    char *s;
00892    struct dundi_result dr2[MAX_RESULTS];
00893    struct dundi_request dr;
00894    struct dundi_hint_metadata hmd;
00895 
00896    struct dundi_mapping *cur;
00897    int mapcount;
00898    int skipfirst = 0;
00899    
00900    pthread_t lookupthread;
00901 
00902    memset(&dr2, 0, sizeof(dr2));
00903    memset(&dr, 0, sizeof(dr));
00904    memset(&hmd, 0, sizeof(hmd));
00905    
00906    /* Forge request structure to hold answers for cache */
00907    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00908    dr.dr = dr2;
00909    dr.maxcount = MAX_RESULTS;
00910    dr.expiration = dundi_cache_time;
00911    dr.hmd = &hmd;
00912    dr.pfds[0] = dr.pfds[1] = -1;
00913    trans->parent = &dr;
00914    ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
00915    ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
00916    
00917    for (x=0;x<ies->anscount;x++) {
00918       if (trans->parent->respcount < trans->parent->maxcount) {
00919          /* Make sure it's not already there */
00920          for (z=0;z<trans->parent->respcount;z++) {
00921             if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
00922                 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data)) 
00923                   break;
00924          }
00925          if (z == trans->parent->respcount) {
00926             /* Copy into parent responses */
00927             trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
00928             trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
00929             trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
00930             trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
00931             if (ies->expiration > 0)
00932                trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
00933             else
00934                trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
00935             dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 
00936                sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
00937                &ies->answers[x]->eid);
00938             ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
00939                sizeof(trans->parent->dr[trans->parent->respcount].dest));
00940                ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
00941                sizeof(trans->parent->dr[trans->parent->respcount].tech));
00942             trans->parent->respcount++;
00943             ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);   
00944          } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
00945             /* Update weight if appropriate */
00946             trans->parent->dr[z].weight = ies->answers[x]->weight;
00947          }
00948       } else
00949          ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
00950             trans->parent->number, trans->parent->dcontext);
00951 
00952    }
00953    /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
00954    cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
00955    if (ies->hint)
00956       cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
00957 
00958    totallen = sizeof(struct dundi_query_state);
00959    /* Count matching map entries */
00960    mapcount = 0;
00961    AST_LIST_TRAVERSE(&mappings, cur, list) {
00962       if (!strcasecmp(cur->dcontext, ccontext))
00963          mapcount++;
00964    }
00965    
00966    /* If no maps, return -1 immediately */
00967    if (!mapcount)
00968       return -1;
00969 
00970    if (ies->eidcount > 1) {
00971       /* Since it is a requirement that the first EID is the authenticating host
00972          and the last EID is the root, it is permissible that the first and last EID
00973          could be the same.  In that case, we should go ahead copy only the "root" section
00974          since we will not need it for authentication. */
00975       if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00976          skipfirst = 1;
00977    }
00978 
00979    /* Prepare to run a query and then propagate that as necessary */
00980    totallen += mapcount * sizeof(struct dundi_mapping);
00981    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00982    st = ast_calloc(1, totallen);
00983    if (st) {
00984       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00985       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
00986       st->trans = trans;
00987       st->ttl = ies->ttl - 1;
00988       st->nocache = ies->cbypass;
00989       if (st->ttl < 0)
00990          st->ttl = 0;
00991       s = st->fluffy;
00992       for (x=skipfirst;ies->eids[x];x++) {
00993          st->eids[x-skipfirst] = (dundi_eid *)s;
00994          *st->eids[x-skipfirst] = *ies->eids[x];
00995          st->directs[x-skipfirst] = ies->eid_direct[x];
00996          s += sizeof(dundi_eid);
00997       }
00998       /* Append mappings */
00999       x = 0;
01000       st->maps = (struct dundi_mapping *)s;
01001       AST_LIST_TRAVERSE(&mappings, cur, list) {
01002          if (!strcasecmp(cur->dcontext, ccontext)) {
01003             if (x < mapcount) {
01004                st->maps[x] = *cur;
01005                st->maps[x].list.next = NULL;
01006                x++;
01007             }
01008          }
01009       }
01010       st->nummaps = mapcount;
01011       ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
01012       trans->thread = 1;
01013       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
01014          trans->thread = 0;
01015          ast_log(LOG_WARNING, "Unable to create thread!\n");
01016          ast_free(st);
01017          memset(&ied, 0, sizeof(ied));
01018          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01019          dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
01020          return -1;
01021       }
01022    } else {
01023       ast_log(LOG_WARNING, "Out of memory!\n");
01024       memset(&ied, 0, sizeof(ied));
01025       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01026       dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
01027       return -1;
01028    }
01029    return 0;
01030 }

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3276 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, sched, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by query_transactions().

03277 {
03278    struct dundi_ie_data ied;
03279    int x;
03280    if (!trans->parent) {
03281       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03282       return -1;
03283    }
03284    memset(&ied, 0, sizeof(ied));
03285    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03286    if (!dundi_eid_zero(&trans->us_eid))
03287       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03288    for (x=0;x<trans->eidcount;x++)
03289       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03290    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03291    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03292    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03293    if (trans->autokilltimeout)
03294       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03295    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03296 }

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

Retrieve information on a specific EID.

Definition at line 3893 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03894 {
03895    dundi_eid *avoid[1] = { NULL, };
03896    struct dundi_hint_metadata hmd;
03897    memset(&hmd, 0, sizeof(hmd));
03898    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03899 }

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

References ast_copy_string(), AST_LIST_EMPTY, ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), build_transactions(), dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, optimize_transactions(), and query_transactions().

Referenced by dundi_query_eid(), and dundi_query_thread().

03847 {
03848    int res;
03849    struct dundi_request dr;
03850    dundi_eid *rooteid=NULL;
03851    int x;
03852    int ttlms;
03853    int skipped=0;
03854    int foundcache=0;
03855    struct timeval start;
03856    
03857    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03858 
03859    for (x=0;avoid[x];x++)
03860       rooteid = avoid[x];
03861    /* Now perform real check */
03862    memset(&dr, 0, sizeof(dr));
03863    dr.hmd = hmd;
03864    dr.dei = dei;
03865    dr.pfds[0] = dr.pfds[1] = -1;
03866    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03867    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03868    if (rooteid)
03869       dr.root_eid = *rooteid;
03870    /* Create transactions */
03871    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03872 
03873    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03874       do this earlier because we didn't know if we were going to have transactions
03875       or not. */
03876    if (!ttl) {
03877       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03878       return 0;
03879    }
03880       
03881    /* Optimize transactions */
03882    optimize_transactions(&dr, 9999);
03883    /* Actually perform transactions */
03884    query_transactions(&dr);
03885    /* Wait for transaction to come back */
03886    start = ast_tvnow();
03887    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03888       usleep(1);
03889    res = dr.respcount;
03890    return res;
03891 }

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

Definition at line 3999 of file pbx_dundi.c.

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

04000 {
04001    struct ast_module_user *u;
04002    AST_DECLARE_APP_ARGS(args,
04003       AST_APP_ARG(number);
04004       AST_APP_ARG(context);
04005       AST_APP_ARG(options);
04006    );
04007    struct ast_flags opts = { 0, };
04008    char *parse;
04009    struct dundi_result_datastore *drds;
04010    struct ast_datastore *datastore;
04011 
04012    u = ast_module_user_add(chan);
04013 
04014    if (ast_strlen_zero(data)) {
04015       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
04016       ast_module_user_remove(u);
04017       return -1;
04018    }
04019 
04020    if (!chan) {
04021       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
04022       ast_module_user_remove(u);
04023       return -1;
04024    }
04025 
04026    parse = ast_strdupa(data);
04027 
04028    AST_STANDARD_APP_ARGS(args, parse);
04029    
04030    if (!ast_strlen_zero(args.options))
04031       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
04032 
04033    if (ast_strlen_zero(args.context))
04034       args.context = "e164";
04035 
04036    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
04037       ast_module_user_remove(u);
04038       return -1;
04039    }
04040 
04041    drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
04042    snprintf(buf, len, "%u", drds->id);
04043 
04044    if (!(datastore = ast_channel_datastore_alloc(&dundi_result_datastore_info, buf))) {
04045       drds_destroy(drds);
04046       ast_module_user_remove(u);
04047       return -1;
04048    }
04049 
04050    datastore->data = drds;
04051 
04052    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, 
04053       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04054 
04055    if (drds->num_results > 0)
04056       sort_results(drds->results, drds->num_results);
04057 
04058    ast_channel_lock(chan);
04059    ast_channel_datastore_add(chan, datastore);
04060    ast_channel_unlock(chan);
04061 
04062    ast_module_user_remove(u);
04063 
04064    return 0;
04065 }

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

Definition at line 699 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), 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, FLAG_DEAD, dundi_query_state::reqeid, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

00700 {
00701    struct dundi_query_state *st = data;
00702    struct dundi_entity_info dei;
00703    struct dundi_ie_data ied;
00704    struct dundi_hint_metadata hmd;
00705    char eid_str[20];
00706    int res;
00707 
00708    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00709       st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00710    memset(&ied, 0, sizeof(ied));
00711    memset(&dei, 0, sizeof(dei));
00712    memset(&hmd, 0, sizeof(hmd));
00713    if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00714       /* Ooh, it's us! */
00715       ast_debug(1, "Neat, someone look for us!\n");
00716       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00717       ast_copy_string(dei.org, org, sizeof(dei.org));
00718       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00719       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00720       ast_copy_string(dei.country, country, sizeof(dei.country));
00721       ast_copy_string(dei.email, email, sizeof(dei.email));
00722       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00723       res = 1;
00724    } else {
00725       /* If we do not have a canonical result, keep looking */
00726       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00727    }
00728    AST_LIST_LOCK(&peers);
00729    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00730       ast_debug(1, "Our transaction went away!\n");
00731       st->trans->thread = 0;
00732       destroy_trans(st->trans, 0);
00733    } else {
00734       if (res) {
00735          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00736          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00737          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00738          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00739          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00740          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00741          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00742          if (!ast_strlen_zero(dei.ipaddr))
00743             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00744       }
00745       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00746       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00747       st->trans->thread = 0;
00748    }
00749    AST_LIST_UNLOCK(&peers);
00750    ast_free(st);
00751    return NULL;   
00752 }

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

Definition at line 367 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

Definition at line 4079 of file pbx_dundi.c.

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

04080 {
04081    struct ast_module_user *u;
04082    AST_DECLARE_APP_ARGS(args,
04083       AST_APP_ARG(id);
04084       AST_APP_ARG(resultnum);
04085    );
04086    char *parse;
04087    unsigned int num;
04088    struct dundi_result_datastore *drds;
04089    struct ast_datastore *datastore;
04090    int res = -1;
04091 
04092    u = ast_module_user_add(chan);
04093 
04094    if (ast_strlen_zero(data)) {
04095       ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n");
04096       goto finish;
04097    }
04098 
04099    if (!chan) {
04100       ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n");
04101       goto finish;
04102    }
04103 
04104    parse = ast_strdupa(data);
04105 
04106    AST_STANDARD_APP_ARGS(args, parse);
04107 
04108    if (ast_strlen_zero(args.id)) {
04109       ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n");
04110       goto finish;
04111    }
04112 
04113    if (ast_strlen_zero(args.resultnum)) {
04114       ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n");
04115       goto finish;
04116    }
04117    
04118    ast_channel_lock(chan);
04119    datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id);
04120    ast_channel_unlock(chan);
04121 
04122    if (!datastore) {
04123       ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id);
04124       goto finish;
04125    }
04126 
04127    drds = datastore->data;
04128 
04129    if (!strcasecmp(args.resultnum, "getnum")) {
04130       snprintf(buf, len, "%u", drds->num_results);
04131       res = 0;
04132       goto finish;
04133    }
04134 
04135    if (sscanf(args.resultnum, "%u", &num) != 1) {
04136       ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n", 
04137          args.resultnum);
04138       goto finish;
04139    }
04140 
04141    if (num && num <= drds->num_results) {
04142       snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest);
04143       res = 0;
04144    } else
04145       ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id);
04146 
04147 finish:
04148    ast_module_user_remove(u);
04149 
04150    return res;
04151 }

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

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

03060 {
03061    struct dundi_packet *pack = (struct dundi_packet *)data;
03062    int res;
03063    AST_LIST_LOCK(&peers);
03064    if (pack->retrans < 1) {
03065       pack->retransid = -1;
03066       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
03067          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
03068             ast_inet_ntoa(pack->parent->addr.sin_addr), 
03069             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
03070       destroy_trans(pack->parent, 1);
03071       res = 0;
03072    } else {
03073       /* Decrement retransmission, try again */
03074       pack->retrans--;
03075       dundi_xmit(pack);
03076       res = 1;
03077    }
03078    AST_LIST_UNLOCK(&peers);
03079    return res;
03080 }

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

Definition at line 3082 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, 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_eid_to_str(), 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(), dundi_packet::list, LOG_NOTICE, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::packets, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, dundi_transaction::retranstimer, sched, 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_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().

03083 {
03084    struct dundi_packet *pack;
03085    int res;
03086    int len;
03087    char eid_str[20];
03088    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
03089    /* Reserve enough space for encryption */
03090    if (ast_test_flag(trans, FLAG_ENCRYPT))
03091       len += 384;
03092    pack = ast_calloc(1, len);
03093    if (pack) {
03094       pack->h = (struct dundi_hdr *)(pack->data);
03095       if (cmdresp != DUNDI_COMMAND_ACK) {
03096          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
03097          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
03098          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
03099       }
03100       pack->parent = trans;
03101       pack->h->strans = htons(trans->strans);
03102       pack->h->dtrans = htons(trans->dtrans);
03103       pack->h->iseqno = trans->iseqno;
03104       pack->h->oseqno = trans->oseqno;
03105       pack->h->cmdresp = cmdresp;
03106       pack->datalen = sizeof(struct dundi_hdr);
03107       if (ied) {
03108          memcpy(pack->h->ies, ied->buf, ied->pos);
03109          pack->datalen += ied->pos;
03110       } 
03111       if (final) {
03112          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
03113          ast_set_flag(trans, FLAG_FINAL);
03114       }
03115       pack->h->cmdflags = flags;
03116       if (cmdresp != DUNDI_COMMAND_ACK) {
03117          trans->oseqno++;
03118          trans->oseqno = trans->oseqno % 256;
03119       }
03120       trans->aseqno = trans->iseqno;
03121       /* If we have their public key, encrypt */
03122       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
03123          switch(cmdresp) {
03124          case DUNDI_COMMAND_REGREQ:
03125          case DUNDI_COMMAND_REGRESPONSE:
03126          case DUNDI_COMMAND_DPDISCOVER:
03127          case DUNDI_COMMAND_DPRESPONSE:
03128          case DUNDI_COMMAND_EIDQUERY:
03129          case DUNDI_COMMAND_EIDRESPONSE:
03130          case DUNDI_COMMAND_PRECACHERQ:
03131          case DUNDI_COMMAND_PRECACHERP:
03132             if (dundidebug)
03133                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
03134             res = dundi_encrypt(trans, pack);
03135             break;
03136          default:
03137             res = 0;
03138          }
03139       } else 
03140          res = 0;
03141       if (!res) 
03142          res = dundi_xmit(pack);
03143       if (res)
03144          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03145             
03146       if (cmdresp == DUNDI_COMMAND_ACK)
03147          ast_free(pack);
03148       return res;
03149    }
03150    return -1;
03151 }

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

Definition at line 2263 of file pbx_dundi.c.

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

02264 {
02265    switch (cmd) {
02266    case CLI_INIT:
02267       e->command = "dundi set debug {on|off}";
02268       e->usage = 
02269          "Usage: dundi set debug {on|off}\n"
02270          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02271       return NULL;
02272    case CLI_GENERATE:
02273       return NULL;
02274    }
02275 
02276    if (a->argc != e->args)
02277       return CLI_SHOWUSAGE;
02278 
02279    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02280       dundidebug = 1;
02281       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02282    } else {
02283       dundidebug = 0;
02284       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02285    }
02286    return CLI_SUCCESS;
02287 }

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

Definition at line 2778 of file pbx_dundi.c.

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

02779 {
02780    char eid_str[20];
02781    switch (cmd) {
02782    case CLI_INIT:
02783       e->command = "dundi show entityid";
02784       e->usage =
02785          "Usage: dundi show entityid\n"
02786          "       Displays the global entityid for this host.\n";
02787       return NULL;
02788    case CLI_GENERATE:
02789       return NULL;
02790    }
02791    if (a->argc != 3)
02792       return CLI_SHOWUSAGE;
02793    AST_LIST_LOCK(&peers);
02794    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02795    AST_LIST_UNLOCK(&peers);
02796    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02797    return CLI_SUCCESS;
02798 }

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

Definition at line 2832 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_flags2str(), ast_cli_args::fd, FORMAT, FORMAT2, get_mapping_weight(), dundi_mapping::list, map, tech2str(), and ast_cli_entry::usage.

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

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

Definition at line 2581 of file pbx_dundi.c.

References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_strlen_zero(), dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_peer_helper(), dundi_eid_to_str(), 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, permission::list, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::model, model2str(), ast_cli_args::n, permission::name, dundi_peer::order, dundi_peer::outkey, dundi_peer::permit, ast_cli_args::pos, dundi_peer::registerid, ast_cli_entry::usage, and ast_cli_args::word.

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

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

Definition at line 2654 of file pbx_dundi.c.

References dundi_peer::addr, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), 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_eid_to_str(), dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, FORMAT, FORMAT2, dundi_peer::lastms, dundi_peer::list, dundi_peer::maxms, dundi_peer::model, model2str(), status, and ast_cli_entry::usage.

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

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

Definition at line 2865 of file pbx_dundi.c.

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

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

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

Definition at line 2800 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_request::dcontext, dundi_eid_to_str(), dundi_eid_zero(), ast_cli_args::fd, FORMAT, FORMAT2, dundi_request::list, dundi_request::maxcount, dundi_request::number, dundi_request::respcount, dundi_request::root_eid, and ast_cli_entry::usage.

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

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

Definition at line 2749 of file pbx_dundi.c.

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

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

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

Definition at line 2315 of file pbx_dundi.c.

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02952 {
02953    int res;
02954    if (dundidebug)
02955       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02956    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02957    if (res < 0) {
02958       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02959          ast_inet_ntoa(pack->parent->addr.sin_addr),
02960          ntohs(pack->parent->addr.sin_port), strerror(errno));
02961    }
02962    if (res > 0)
02963       res = 0;
02964    return res;
02965 }

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

Definition at line 3901 of file pbx_dundi.c.

References ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), ast_test_flag, chan, dundi_result::dest, dr, DUNDI_FLAG_EXISTS, dundi_lookup(), LOG_WARNING, MAX_RESULTS, sort_results(), and dundi_result::tech.

03902 {
03903    char *context;
03904    char *opts;
03905    int results;
03906    int x;
03907    int bypass = 0;
03908    struct ast_module_user *u;
03909    struct dundi_result dr[MAX_RESULTS];
03910 
03911    buf[0] = '\0';
03912 
03913    if (ast_strlen_zero(num)) {
03914       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03915       return -1;
03916    }
03917 
03918    u = ast_module_user_add(chan);
03919 
03920    context = strchr(num, '|');
03921    if (context) {
03922       *context++ = '\0';
03923       opts = strchr(context, '|');
03924       if (opts) {
03925          *opts++ = '\0';
03926          if (strchr(opts, 'b'))
03927             bypass = 1;
03928       }
03929    }
03930 
03931    if (ast_strlen_zero(context))
03932       context = "e164";
03933    
03934    results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
03935    if (results > 0) {
03936       sort_results(dr, results);
03937       for (x = 0; x < results; x++) {
03938          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03939             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03940             break;
03941          }
03942       }
03943    }
03944 
03945    ast_module_user_remove(u);
03946 
03947    return 0;
03948 }

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

Definition at line 1314 of file pbx_dundi.c.

References ast_aes_encrypt.

Referenced by dundi_encrypt().

01315 {
01316    unsigned char curblock[16];
01317    int x;
01318    memcpy(curblock, iv, sizeof(curblock));
01319    while(len > 0) {
01320       for (x=0;x<16;x++)
01321          curblock[x] ^= src[x];
01322       ast_aes_encrypt(curblock, dst, ecx);
01323       memcpy(curblock, dst, sizeof(curblock)); 
01324       dst += 16;
01325       src += 16;
01326       len -= 16;
01327    }
01328    return 0;
01329 }

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

Definition at line 471 of file pbx_dundi.c.

References any_peer, AST_LIST_TRAVERSE, dundi_eid_cmp(), dundi_peer::eid, and empty_eid.

00472 {
00473    struct dundi_peer *cur = NULL;
00474 
00475    if (!eid)
00476       eid = &empty_eid;
00477    
00478    AST_LIST_TRAVERSE(&peers, cur, list) {
00479       if (!dundi_eid_cmp(&cur->eid,eid))
00480          break;
00481    }
00482 
00483    if (!cur && any_peer)
00484       cur = any_peer;
00485 
00486    return cur;
00487 }

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

Definition at line 325 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 515 of file pbx_dundi.c.

References buf, map, MAX_WEIGHT, and pbx_substitute_variables_helper().

Referenced by dundi_lookup_local(), and dundi_show_mappings().

00516 {
00517    char buf[32];
00518 
00519    buf[0] = 0;
00520    if (map->weightstr) {
00521       pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
00522       if (sscanf(buf, "%d", &map->_weight) != 1)
00523          map->_weight = MAX_WEIGHT;
00524    }
00525 
00526    return map->_weight;
00527 }

static int get_trans_id ( void   )  [static]

Definition at line 436 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

00437 {
00438    struct dundi_transaction *t;
00439    int stid = (ast_random() % 32766) + 1;
00440    int tid = stid;
00441 
00442    do {
00443       AST_LIST_TRAVERSE(&alltrans, t, all) {
00444          if (t->strans == tid) 
00445             break;
00446       }
00447       if (!t)
00448          return tid;
00449       tid = (tid % 32766) + 1;
00450    } while (tid != stid);
00451 
00452    return 0;
00453 }

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

Definition at line 1521 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, any_peer, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_inet_ntoa(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verb, cache_save(), cache_save_hint(), dundi_hdr::cmdresp, dundi_request::dcontext, deep_copy_peer(), dundi_result::dest, do_register_expire(), dundi_request::dr, 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_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, dundi_eid_to_str(), dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_peer::dynamic, dundi_peer::eid, dundi_request::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, has_permission(), dundi_request::hmd, dundi_hdr::ies, ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, permission::list, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_peer::model, dundi_request::number, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_ie_data::pos, qualify_peer(), dundi_peer::registerexpire, dundi_request::respcount, sched, tech2str(), dundi_result::techint, dundi_transaction::them_eid, dundi_peer::us_eid, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by handle_frame().

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

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

Definition at line 1981 of file pbx_dundi.c.

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

01982 {
01983    struct dundi_transaction *trans;
01984    trans = find_transaction(h, sin);
01985    if (!trans) {
01986       dundi_reject(h, sin);
01987       return 0;
01988    }
01989    /* Got a transaction, see where this header fits in */
01990    if (h->oseqno == trans->iseqno) {
01991       /* Just what we were looking for...  Anything but ack increments iseqno */
01992       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
01993          /* If final, we're done */
01994          destroy_trans(trans, 0);
01995          return 0;
01996       }
01997       if (h->cmdresp != DUNDI_COMMAND_ACK) {
01998          trans->oiseqno = trans->iseqno;
01999          trans->iseqno++;
02000          handle_command_response(trans, h, datalen, 0);
02001       }
02002       if (trans->aseqno != trans->iseqno) {
02003          dundi_ack(trans, h->cmdresp & 0x80);
02004          trans->aseqno = trans->iseqno;
02005       }
02006       /* Delete any saved last transmissions */
02007       destroy_packets(&trans->lasttrans);
02008       if (h->cmdresp & 0x80) {
02009          /* Final -- destroy now */
02010          destroy_trans(trans, 0);
02011       }
02012    } else if (h->oseqno == trans->oiseqno) {
02013       /* Last incoming sequence number -- send ACK without processing */
02014       dundi_ack(trans, 0);
02015    } else {
02016       /* Out of window -- simply drop */
02017       ast_debug(1, "Dropping packet out of window!\n");
02018    }
02019    return 0;
02020 }

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

Definition at line 281 of file pbx_dundi.c.

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

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

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

static int load_module ( void   )  [static]

Definition at line 4864 of file pbx_dundi.c.

References ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_netsock_set_qos(), ast_register_switch(), ast_verb, cli_dundi, dundi_debug_output(), dundi_error_output(), dundi_function, DUNDI_PORT, dundi_query_function, dundi_result_function, dundi_set_error(), dundi_set_output(), dundi_switch, errno, io, io_context_create(), LOG_ERROR, sched, sched_context_create(), set_config(), and start_network_thread().

04865 {
04866    struct sockaddr_in sin;
04867 
04868    dundi_set_output(dundi_debug_output);
04869    dundi_set_error(dundi_error_output);
04870    
04871    sin.sin_family = AF_INET;
04872    sin.sin_port = ntohs(DUNDI_PORT);
04873    sin.sin_addr.s_addr = INADDR_ANY;
04874 
04875    /* Make a UDP socket */
04876    io = io_context_create();
04877    sched = sched_context_create();
04878    
04879    if (!io || !sched)
04880       return AST_MODULE_LOAD_FAILURE;
04881 
04882    if (set_config("dundi.conf", &sin, 0))
04883       return AST_MODULE_LOAD_DECLINE;
04884 
04885    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04886    
04887    if (netsocket < 0) {
04888       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04889       return AST_MODULE_LOAD_FAILURE;
04890    }
04891    if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {
04892       ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", 
04893          ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
04894       return AST_MODULE_LOAD_FAILURE;
04895    }
04896    
04897    ast_netsock_set_qos(netsocket, tos, 0, "DUNDi");
04898    
04899    if (start_network_thread()) {
04900       ast_log(LOG_ERROR, "Unable to start network thread\n");
04901       close(netsocket);
04902       return AST_MODULE_LOAD_FAILURE;
04903    }
04904    
04905    ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(*cli_dundi));
04906    if (ast_register_switch(&dundi_switch))
04907       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04908    ast_custom_function_register(&dundi_function);
04909    ast_custom_function_register(&dundi_query_function);
04910    ast_custom_function_register(&dundi_result_function);
04911    
04912    ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04913 
04914    return AST_MODULE_LOAD_SUCCESS;
04915 }

static void load_password ( void   )  [static]

Definition at line 2078 of file pbx_dundi.c.

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

Referenced by set_config().

02079 {
02080    char *current=NULL;
02081    char *last=NULL;
02082    char tmp[256];
02083    time_t expired;
02084    
02085    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02086    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02087       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02088       current = strchr(tmp, ';');
02089       if (!current)
02090          current = tmp;
02091       else {
02092          *current = '\0';
02093          current++;
02094       };
02095       if ((time(NULL) - expired) < 0) {
02096          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02097             expired = time(NULL) + DUNDI_SECRET_TIME;
02098       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02099          last = current;
02100          current = NULL;
02101       } else {
02102          last = NULL;
02103          current = NULL;
02104       }
02105    }
02106    if (current) {
02107       /* Current key is still valid, just setup rotatation properly */
02108       ast_copy_string(cursecret, current, sizeof(cursecret));
02109       rotatetime = expired;
02110    } else {
02111       /* Current key is out of date, rotate or eliminate all together */
02112       build_secret(cursecret, sizeof(cursecret));
02113       save_secret(cursecret, last);
02114    }
02115 }

static void mark_mappings ( void   )  [static]

Definition at line 4176 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

04177 {
04178    struct dundi_mapping *map;
04179    
04180    AST_LIST_LOCK(&peers);
04181    AST_LIST_TRAVERSE(&mappings, map, list) {
04182       map->dead = 1;
04183    }
04184    AST_LIST_UNLOCK(&peers);
04185 }

static void mark_peers ( void   )  [static]

Definition at line 4166 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

04167 {
04168    struct dundi_peer *peer;
04169    AST_LIST_LOCK(&peers);
04170    AST_LIST_TRAVERSE(&peers, peer, list) {
04171       peer->dead = 1;
04172    }
04173    AST_LIST_UNLOCK(&peers);
04174 }

static char* model2str ( int  model  )  [static]

Definition at line 2387 of file pbx_dundi.c.

References DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, and DUNDI_MODEL_SYMMETRIC.

Referenced by dundi_show_peer(), and dundi_show_peers().

02388 {
02389    switch(model) {
02390    case DUNDI_MODEL_INBOUND:
02391       return "Inbound";
02392    case DUNDI_MODEL_OUTBOUND:
02393       return "Outbound";
02394    case DUNDI_MODEL_SYMMETRIC:
02395       return "Symmetric";
02396    default:
02397       return "Unknown";
02398    }
02399 }

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

Definition at line 2134 of file pbx_dundi.c.

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

02135 {
02136    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
02137       from the network, and queue them for delivery to the channels */
02138    int res;
02139    /* Establish I/O callback for socket read */
02140    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02141    
02142    while (!dundi_shutdown) {
02143       res = ast_sched_wait(sched);
02144       if ((res > 1000) || (res < 0))
02145          res = 1000;
02146       res = ast_io_wait(io, res);
02147       if (res >= 0) {
02148          AST_LIST_LOCK(&peers);
02149          ast_sched_runq(sched);
02150          AST_LIST_UNLOCK(&peers);
02151       }
02152       check_password();
02153    }
02154 
02155    netthreadid = AST_PTHREADT_NULL;
02156    
02157    return NULL;
02158 }

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

Definition at line 3357 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, dr, dundi_eid_cmp(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), dundi_peer::include, dundi_peer::list, dundi_peer::order, dundi_transaction::them_eid, and dundi_transaction::us_eid.

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

03358 {
03359    /* Minimize the message propagation through DUNDi by
03360       alerting the network to hops which should be not be considered */
03361    struct dundi_transaction *trans;
03362    struct dundi_peer *peer;
03363    dundi_eid tmp;
03364    int x;
03365    int needpush;
03366 
03367    AST_LIST_LOCK(&peers);
03368    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03369       /* Pop off the true root */
03370       if (trans->eidcount) {
03371          tmp = trans->eids[--trans->eidcount];
03372          needpush = 1;
03373       } else {
03374          tmp = trans->us_eid;
03375          needpush = 0;
03376       }
03377 
03378       AST_LIST_TRAVERSE(&peers, peer, list) {
03379          if (has_permission(&peer->include, dr->dcontext) && 
03380              dundi_eid_cmp(&peer->eid, &trans->them_eid) &&
03381             (peer->order <= order)) {
03382             /* For each other transaction, make sure we don't
03383                ask this EID about the others if they're not
03384                already in the list */
03385             if (!dundi_eid_cmp(&tmp, &peer->eid)) 
03386                x = -1;
03387             else {
03388                for (x=0;x<trans->eidcount;x++) {
03389                   if (!dundi_eid_cmp(&trans->eids[x], &peer->eid))
03390                      break;
03391                }
03392             }
03393             if (x == trans->eidcount) {
03394                /* Nope not in the list, if needed, add us at the end since we're the source */
03395                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03396                   trans->eids[trans->eidcount++] = peer->eid;
03397                   /* Need to insert the real root (or us) at the bottom now as
03398                      a requirement now.  */
03399                   needpush = 1;
03400                }
03401             }
03402          }
03403       }
03404       /* If necessary, push the true root back on the end */
03405       if (needpush)
03406          trans->eids[trans->eidcount++] = tmp;
03407    }
03408    AST_LIST_UNLOCK(&peers);
03409 
03410    return 0;
03411 }

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

Definition at line 4389 of file pbx_dundi.c.

References dundi_peer::addr, ast_db_get(), ast_sched_add(), do_register_expire(), dundi_eid_to_str(), dundi_peer::eid, inet_aton(), dundi_peer::registerexpire, and sched.

Referenced by build_peer().

04390 {
04391    char data[256];
04392    char *c;
04393    int port, expire;
04394    char eid_str[20];
04395    dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
04396    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04397       c = strchr(data, ':');
04398       if (c) {
04399          *c = '\0';
04400          c++;
04401          if (sscanf(c, "%d:%d", &port, &expire) == 2) {
04402             /* Got it! */
04403             inet_aton(data, &peer->addr.sin_addr);
04404             peer->addr.sin_family = AF_INET;
04405             peer->addr.sin_port = htons(port);
04406             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04407          }
04408       }
04409    }
04410 }

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

Definition at line 3210 of file pbx_dundi.c.

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

Referenced by precache_transactions().

03211 {
03212    struct dundi_ie_data ied;
03213    int x, res;
03214    int max = 999999;
03215    int expiration = dundi_cache_time;
03216    int ouranswers=0;
03217    dundi_eid *avoid[1] = { NULL, };
03218    int direct[1] = { 0, };
03219    struct dundi_result dr[MAX_RESULTS];
03220    struct dundi_hint_metadata hmd;
03221    if (!trans->parent) {
03222       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03223       return -1;
03224    }
03225    memset(&hmd, 0, sizeof(hmd));
03226    memset(&dr, 0, sizeof(dr));
03227    /* Look up the answers we're going to include */
03228    for (x=0;x<mapcount;x++)
03229       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03230    if (ouranswers < 0)
03231       ouranswers = 0;
03232    for (x=0;x<ouranswers;x++) {
03233       if (dr[x].weight < max)
03234          max = dr[x].weight;
03235    }
03236    if (max) {
03237       /* If we do not have a canonical result, keep looking */
03238       res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, trans->parent->dcontext, trans->parent->number, trans->ttl, 1, &hmd, &expiration, 0, 1, &trans->them_eid, avoid, direct);
03239       if (res > 0) {
03240          /* Append answer in result */
03241          ouranswers += res;
03242       }
03243    }
03244    
03245    if (ouranswers > 0) {
03246       *foundanswers += ouranswers;
03247       memset(&ied, 0, sizeof(ied));
03248       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03249       if (!dundi_eid_zero(&trans->us_eid))
03250          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03251       for (x=0;x<trans->eidcount;x++)
03252          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03253       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03254       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03255       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03256       for (x=0;x<ouranswers;x++) {
03257          /* Add answers */
03258          if (dr[x].expiration && (expiration > dr[x].expiration))
03259             expiration = dr[x].expiration;
03260          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03261       }
03262       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03263       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03264       if (trans->autokilltimeout)
03265          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03266       if (expiration < *minexp)
03267          *minexp = expiration;
03268       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03269    } else {
03270       /* Oops, nothing to send... */
03271       destroy_trans(trans, 0);
03272       return 0;
03273    }
03274 }

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

Definition at line 3309 of file pbx_dundi.c.

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

Referenced by dundi_precache_internal().

03310 {
03311    struct dundi_transaction *trans;
03312 
03313    /* Mark all as "in thread" so they don't disappear */
03314    AST_LIST_LOCK(&peers);
03315    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03316       if (trans->thread)
03317          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03318       trans->thread = 1;
03319    }
03320    AST_LIST_UNLOCK(&peers);
03321 
03322    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03323       if (!ast_test_flag(trans, FLAG_DEAD))
03324          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03325    }
03326 
03327    /* Cleanup any that got destroyed in the mean time */
03328    AST_LIST_LOCK(&peers);
03329    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03330       trans->thread = 0;
03331       if (ast_test_flag(trans, FLAG_DEAD)) {
03332          ast_debug(1, "Our transaction went away!\n");
03333          /* This is going to remove the transaction from the dundi_request's list, as well
03334           * as the global transactions list */
03335          destroy_trans(trans, 0);
03336       }
03337    }
03338    AST_LIST_TRAVERSE_SAFE_END
03339    AST_LIST_UNLOCK(&peers);
03340 
03341    return 0;
03342 }

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

Definition at line 2160 of file pbx_dundi.c.

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

Referenced by start_network_thread().

02161 {
02162    struct ast_db_entry *db_entry, *db_tree;
02163    int striplen = sizeof("/dundi/cache");
02164    time_t now;
02165    
02166    while (!dundi_shutdown) {
02167       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
02168 
02169       time(&now);
02170 
02171       db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
02172       for (; db_entry; db_entry = db_entry->next) {
02173          time_t expiry;
02174 
02175          if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
02176             if (expiry < now) {
02177                ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
02178                ast_db_del("dundi/cache", db_entry->key + striplen);
02179             }
02180          }
02181       }
02182       ast_db_freetree(db_tree);
02183 
02184       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
02185       pthread_testcancel();
02186       sleep(60);
02187       pthread_testcancel();
02188    }
02189    
02190    clearcachethreadid = AST_PTHREADT_NULL;
02191    return NULL;
02192 }

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

Definition at line 2194 of file pbx_dundi.c.

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

Referenced by start_network_thread().

02195 {
02196    struct dundi_precache_queue *qe;
02197    time_t now;
02198    char context[256];
02199    char number[256];
02200    int run;
02201 
02202    while (!dundi_shutdown) {
02203       time(&now);
02204       run = 0;
02205       AST_LIST_LOCK(&pcq);
02206       if ((qe = AST_LIST_FIRST(&pcq))) {
02207          if (!qe->expiration) {
02208             /* Gone...  Remove... */
02209             AST_LIST_REMOVE_HEAD(&pcq, list);
02210             ast_free(qe);
02211          } else if (qe->expiration < now) {
02212             /* Process this entry */
02213             qe->expiration = 0;
02214             ast_copy_string(context, qe->context, sizeof(context));
02215             ast_copy_string(number, qe->number, sizeof(number));
02216             run = 1;
02217          }
02218       }
02219       AST_LIST_UNLOCK(&pcq);
02220       if (run) {
02221          dundi_precache(context, number);
02222       } else
02223          sleep(1);
02224    }
02225 
02226    precachethreadid = AST_PTHREADT_NULL;
02227 
02228    return NULL;
02229 }

static void prune_mappings ( void   )  [static]

Definition at line 4228 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

04229 {
04230    struct dundi_mapping *map;
04231 
04232    AST_LIST_LOCK(&peers);
04233    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
04234       if (map->dead) {
04235          AST_LIST_REMOVE_CURRENT(list);
04236          destroy_map(map);
04237       }
04238    }
04239    AST_LIST_TRAVERSE_SAFE_END;
04240    AST_LIST_UNLOCK(&peers);
04241 }

static void prune_peers ( void   )  [static]

Definition at line 4213 of file pbx_dundi.c.

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

04214 {
04215    struct dundi_peer *peer;
04216 
04217    AST_LIST_LOCK(&peers);
04218    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
04219       if (peer->dead) {
04220          AST_LIST_REMOVE_CURRENT(list);
04221          destroy_peer(peer);
04222       }
04223    }
04224    AST_LIST_TRAVERSE_SAFE_END;
04225    AST_LIST_UNLOCK(&peers);
04226 }

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

Definition at line 4366 of file pbx_dundi.c.

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

Referenced by do_qualify(), and handle_command_response().

04367 {
04368    int when;
04369    AST_SCHED_DEL(sched, peer->qualifyid);
04370    if (peer->qualtrans)
04371       destroy_trans(peer->qualtrans, 0);
04372    peer->qualtrans = NULL;
04373    if (peer->maxms > 0) {
04374       when = 60000;
04375       if (peer->lastms < 0)
04376          when = 10000;
04377       if (schedonly)
04378          when = 5000;
04379       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04380       if (!schedonly)
04381          peer->qualtrans = create_transaction(peer);
04382       if (peer->qualtrans) {
04383          peer->qualtx = ast_tvnow();
04384          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04385          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04386       }
04387    }
04388 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3344 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, dundi_query(), and dundi_transaction::parentlist.

Referenced by dundi_query_eid_internal().

03345 {
03346    struct dundi_transaction *trans;
03347 
03348    AST_LIST_LOCK(&peers);
03349    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03350       dundi_query(trans);
03351    }
03352    AST_LIST_UNLOCK(&peers);
03353 
03354    return 0;
03355 }

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

Definition at line 3528 of file pbx_dundi.c.

References ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::crc32, dundi_request::dcontext, dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_request::list, dundi_request::number, and dundi_request::root_eid.

Referenced by dundi_lookup_internal().

03529 {
03530    struct dundi_request *cur;
03531    int res=0;
03532    char eid_str[20];
03533    AST_LIST_LOCK(&peers);
03534    AST_LIST_TRAVERSE(&requests, cur, list) {
03535       ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03536          dr->dcontext, dr->number);
03537       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03538           !strcasecmp(cur->number, dr->number) &&
03539           (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03540          ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 
03541             cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03542          *pending = cur;
03543          res = 1;
03544          break;
03545       }
03546    }
03547    if (!res) {
03548       ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 
03549             dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03550       /* Go ahead and link us in since nobody else is searching for this */
03551       AST_LIST_INSERT_HEAD(&requests, dr, list);
03552       *pending = NULL;
03553    }
03554    AST_LIST_UNLOCK(&peers);
03555    return res;
03556 }

static int reload ( void   )  [static]

Definition at line 4854 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04855 {
04856    struct sockaddr_in sin;
04857 
04858    if (set_config("dundi.conf", &sin, 1))
04859       return AST_MODULE_LOAD_FAILURE;
04860 
04861    return AST_MODULE_LOAD_SUCCESS;
04862 }

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

Definition at line 3707 of file pbx_dundi.c.

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

Referenced by dundi_precache_full(), and dundi_precache_internal().

03708 {
03709    int len;
03710    struct dundi_precache_queue *qe, *prev;
03711 
03712    AST_LIST_LOCK(&pcq);
03713    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03714       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03715          AST_LIST_REMOVE_CURRENT(list);
03716          break;
03717       }
03718    }
03719    AST_LIST_TRAVERSE_SAFE_END;
03720    if (!qe) {
03721       len = sizeof(*qe);
03722       len += strlen(number) + 1;
03723       len += strlen(context) + 1;
03724       if (!(qe = ast_calloc(1, len))) {
03725          AST_LIST_UNLOCK(&pcq);
03726          return;
03727       }
03728       strcpy(qe->number, number);
03729       qe->context = qe->number + strlen(number) + 1;
03730       strcpy(qe->context, context);
03731    }
03732    time(&qe->expiration);
03733    qe->expiration += expiration;
03734    if ((prev = AST_LIST_FIRST(&pcq))) {
03735       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03736          prev = AST_LIST_NEXT(prev, list);
03737       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03738    } else
03739       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03740    AST_LIST_UNLOCK(&pcq);
03741 }

static int rescomp ( const void *  a,
const void *  b 
) [static]

Definition at line 2423 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02424 {
02425    const struct dundi_result *resa, *resb;
02426    resa = a;
02427    resb = b;
02428    if (resa->weight < resb->weight)
02429       return -1;
02430    if (resa->weight > resb->weight)
02431       return 1;
02432    return 0;
02433 }

static void reset_global_eid ( void   )  [static]

Definition at line 392 of file pbx_dundi.c.

References ast_debug, dundi_eid_to_str(), _dundi_eid::eid, global_eid, and s.

Referenced by set_config().

00393 {
00394 #if defined(SIOCGIFHWADDR)
00395    int s, x = 0;
00396    char eid_str[20];
00397    struct ifreq ifr;
00398 
00399    s = socket(AF_INET, SOCK_STREAM, 0);
00400    if (s < 0)
00401       return;
00402    for (x = 0; x < 10; x++) {
00403       memset(&ifr, 0, sizeof(ifr));
00404       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
00405       if (ioctl(s, SIOCGIFHWADDR, &ifr))
00406          continue;
00407       memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
00408       ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
00409       close(s);
00410       return;
00411    }
00412    close(s);
00413 #else
00414 #if defined(ifa_broadaddr) && !defined(SOLARIS)
00415    char eid_str[20];
00416    struct ifaddrs *ifap;
00417    
00418    if (getifaddrs(&ifap) == 0) {
00419       struct ifaddrs *p;
00420       for (p = ifap; p; p = p->ifa_next) {
00421          if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
00422             struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
00423             memcpy(&(global_eid.eid), sdp->sdl_data + sdp->sdl_nlen, 6);
00424             ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), p->ifa_name);
00425             freeifaddrs(ifap);
00426             return;
00427          }
00428       }
00429       freeifaddrs(ifap);
00430    }
00431 #endif
00432 #endif
00433    ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
00434 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

Definition at line 455 of file pbx_dundi.c.

References dundi_transaction::aseqno, ast_clear_flag, dundi_transaction::dtrans, FLAG_FINAL, get_trans_id(), dundi_transaction::iseqno, dundi_transaction::oiseqno, dundi_transaction::oseqno, and dundi_transaction::strans.

00456 {
00457    int tid;
00458    tid = get_trans_id();
00459    if (tid < 1)
00460       return -1;
00461    trans->strans = tid;
00462    trans->dtrans = 0;
00463    trans->iseqno = 0;
00464    trans->oiseqno = 0;
00465    trans->oseqno = 0;
00466    trans->aseqno = 0;
00467    ast_clear_flag(trans, FLAG_FINAL);  
00468    return 0;
00469 }

static void save_secret ( const char *  newkey,
const char *  oldkey 
) [static]

Definition at line 2065 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02066 {
02067    char tmp[256];
02068    if (oldkey)
02069       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02070    else
02071       snprintf(tmp, sizeof(tmp), "%s", newkey);
02072    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02073    ast_db_put(secretpath, "secret", tmp);
02074    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02075    ast_db_put(secretpath, "secretexpiry", tmp);
02076 }

static int set_config ( char *  config_file,
struct sockaddr_in *  sin,
int  reload 
) [static]

Definition at line 4678 of file pbx_dundi.c.

References any_peer, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_gethostbyname(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_str2tos(), ast_true(), ast_variable_browse(), build_mapping(), build_peer(), DEFAULT_MAXMS, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), dundi_str_to_eid(), empty_eid, find_peer(), global_eid, hp, ast_variable::lineno, load_password(), LOG_ERROR, LOG_NOTICE, mark_mappings(), mark_peers(), MAXHOSTNAMELEN, ast_variable::name, ast_variable::next, prune_mappings(), prune_peers(), reset_global_eid(), and ast_variable::value.

04679 {
04680    struct ast_config *cfg;
04681    struct ast_variable *v;
04682    char *cat;
04683    int x;
04684    struct ast_flags config_flags = { 0 };
04685    char hn[MAXHOSTNAMELEN] = "";
04686    struct ast_hostent he;
04687    struct hostent *hp;
04688    struct sockaddr_in sin2;
04689    static int last_port = 0;
04690    int globalpcmodel = 0;
04691    dundi_eid testeid;
04692 
04693    if (!(cfg = ast_config_load(config_file, config_flags))) {
04694       ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
04695       return -1;
04696    }
04697 
04698    dundi_ttl = DUNDI_DEFAULT_TTL;
04699    dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
04700    any_peer = NULL;
04701 
04702    ipaddr[0] = '\0';
04703    if (!gethostname(hn, sizeof(hn)-1)) {
04704       hp = ast_gethostbyname(hn, &he);
04705       if (hp) {
04706          memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
04707          ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
04708       } else
04709          ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
04710    } else
04711       ast_log(LOG_WARNING, "Unable to get host name!\n");
04712    AST_LIST_LOCK(&peers);
04713    reset_global_eid();
04714    global_storehistory = 0;
04715    ast_copy_string(secretpath, "dundi", sizeof(secretpath));
04716    v = ast_variable_browse(cfg, "general");
04717    while(v) {
04718       if (!strcasecmp(v->name, "port")){ 
04719          sin->sin_port = ntohs(atoi(v->value));
04720          if(last_port==0){
04721             last_port=sin->sin_port;
04722          } else if(sin->sin_port != last_port)
04723             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
04724       } else if (!strcasecmp(v->name, "bindaddr")) {
04725          struct hostent *hp;
04726          struct ast_hostent he;
04727          hp = ast_gethostbyname(v->value, &he);
04728          if (hp) {
04729             memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
04730          } else
04731             ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
04732       } else if (!strcasecmp(v->name, "authdebug")) {
04733          authdebug = ast_true(v->value);
04734       } else if (!strcasecmp(v->name, "ttl")) {
04735          if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
04736             dundi_ttl = x;
04737          } else {
04738             ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
04739                v->value, v->lineno, DUNDI_DEFAULT_TTL);
04740          }
04741       } else if (!strcasecmp(v->name, "autokill")) {
04742          if (sscanf(v->value, "%d", &x) == 1) {
04743             if (x >= 0)
04744                global_autokilltimeout = x;
04745             else
04746                ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
04747          } else if (ast_true(v->value)) {
04748             global_autokilltimeout = DEFAULT_MAXMS;
04749          } else {
04750             global_autokilltimeout = 0;
04751          }
04752       } else if (!strcasecmp(v->name, "entityid")) {
04753          if (!dundi_str_to_eid(&testeid, v->value))
04754             global_eid = testeid;
04755          else
04756             ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
04757       } else if (!strcasecmp(v->name, "tos")) {
04758          if (ast_str2tos(v->value, &tos)) 
04759             ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04760       } else if (!strcasecmp(v->name, "department")) {
04761          ast_copy_string(dept, v->value, sizeof(dept));
04762       } else if (!strcasecmp(v->name, "organization")) {
04763          ast_copy_string(org, v->value, sizeof(org));
04764       } else if (!strcasecmp(v->name, "locality")) {
04765          ast_copy_string(locality, v->value, sizeof(locality));
04766       } else if (!strcasecmp(v->name, "stateprov")) {
04767          ast_copy_string(stateprov, v->value, sizeof(stateprov));
04768       } else if (!strcasecmp(v->name, "country")) {
04769          ast_copy_string(country, v->value, sizeof(country));
04770       } else if (!strcasecmp(v->name, "email")) {
04771          ast_copy_string(email, v->value, sizeof(email));
04772       } else if (!strcasecmp(v->name, "phone")) {
04773          ast_copy_string(phone, v->value, sizeof(phone));
04774       } else if (!strcasecmp(v->name, "storehistory")) {
04775          global_storehistory = ast_true(v->value);
04776       } else if (!strcasecmp(v->name, "cachetime")) {
04777          if ((sscanf(v->value, "%d", &x) == 1)) {
04778             dundi_cache_time = x;
04779          } else {
04780             ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
04781                v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
04782          }
04783       }
04784       v = v->next;
04785    }
04786    AST_LIST_UNLOCK(&peers);
04787    mark_mappings();
04788    v = ast_variable_browse(cfg, "mappings");
04789    while(v) {
04790       build_mapping(v->name, v->value);
04791       v = v->next;
04792    }
04793    prune_mappings();
04794    mark_peers();
04795    cat = ast_category_browse(cfg, NULL);
04796    while(cat) {
04797       if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
04798          /* Entries */
04799          if (!dundi_str_to_eid(&testeid, cat))
04800             build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
04801          else if (!strcasecmp(cat, "*")) {
04802             build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel);
04803             any_peer = find_peer(NULL);
04804          } else
04805             ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
04806       }
04807       cat = ast_category_browse(cfg, cat);
04808    }
04809    prune_peers();
04810    ast_config_destroy(cfg);
04811    load_password();
04812    if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
04813       dundi_precache_full();
04814    return 0;
04815 }

static int socket_read ( int *  id,
int  fd,
short  events,
void *  cbdata 
) [static]

Definition at line 2022 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), buf, dundi_showframe(), errno, handle_frame(), len(), LOG_WARNING, and MAX_PACKET_SIZE.

02023 {
02024    struct sockaddr_in sin;
02025    int res;
02026    struct dundi_hdr *h;
02027    char buf[MAX_PACKET_SIZE];
02028    socklen_t len = sizeof(sin);
02029    
02030    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
02031    if (res < 0) {
02032       if (errno != ECONNREFUSED)
02033          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
02034       return 1;
02035    }
02036    if (res < sizeof(struct dundi_hdr)) {
02037       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
02038       return 1;
02039    }
02040    buf[res] = '\0';
02041    h = (struct dundi_hdr *) buf;
02042    if (dundidebug)
02043       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
02044    AST_LIST_LOCK(&peers);
02045    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
02046    AST_LIST_UNLOCK(&peers);
02047    return 1;
02048 }

static void sort_results ( struct dundi_result results,
int  count 
) [static]

Definition at line 2435 of file pbx_dundi.c.

References rescomp().

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

02436 {
02437    qsort(results, count, sizeof(results[0]), rescomp);
02438 }

static int start_network_thread ( void   )  [static]

Definition at line 2231 of file pbx_dundi.c.

References ast_pthread_create_background, network_thread(), process_clearcache(), and process_precache().

static int str2tech ( char *  str  )  [static]

Definition at line 310 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

00311 {
00312    if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) 
00313       return DUNDI_PROTO_IAX;
00314    else if (!strcasecmp(str, "SIP"))
00315       return DUNDI_PROTO_SIP;
00316    else if (!strcasecmp(str, "H323"))
00317       return DUNDI_PROTO_H323;
00318    else
00319       return -1;
00320 }

static char* tech2str ( int  tech  )  [static]

Definition at line 294 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, DUNDI_PROTO_NONE, and DUNDI_PROTO_SIP.

Referenced by cache_lookup_internal(), dundi_lookup_local(), dundi_prop_precache(), dundi_show_mappings(), and handle_command_response().

00295 {
00296    switch(tech) {
00297    case DUNDI_PROTO_NONE:
00298       return "None";
00299    case DUNDI_PROTO_IAX:
00300       return "IAX2";
00301    case DUNDI_PROTO_SIP:
00302       return "SIP";
00303    case DUNDI_PROTO_H323:
00304       return "H323";
00305    default:
00306       return "Unknown";
00307    }
00308 }

static int unload_module ( void   )  [static]

Definition at line 4817 of file pbx_dundi.c.

References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_module_user_hangup_all, AST_PTHREADT_NULL, ast_unregister_switch(), cli_dundi, dundi_function, dundi_query_function, dundi_result_function, dundi_switch, io, io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), sched, and sched_context_destroy().

04818 {
04819    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid, previous_clearcachethreadid = clearcachethreadid;
04820    ast_module_user_hangup_all();
04821 
04822    /* Stop all currently running threads */
04823    dundi_shutdown = 1;
04824    if (previous_netthreadid != AST_PTHREADT_NULL) {
04825       pthread_kill(previous_netthreadid, SIGURG);
04826       pthread_join(previous_netthreadid, NULL);
04827    }
04828    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04829       pthread_kill(previous_precachethreadid, SIGURG);
04830       pthread_join(previous_precachethreadid, NULL);
04831    }
04832    if (previous_clearcachethreadid != AST_PTHREADT_NULL) {
04833       pthread_cancel(previous_clearcachethreadid);
04834       pthread_join(previous_clearcachethreadid, NULL);
04835    }
04836 
04837    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04838    ast_unregister_switch(&dundi_switch);
04839    ast_custom_function_unregister(&dundi_function);
04840    ast_custom_function_unregister(&dundi_query_function);
04841    ast_custom_function_unregister(&dundi_result_function);
04842    close(netsocket);
04843    io_context_destroy(io);
04844    sched_context_destroy(sched);
04845 
04846    mark_mappings();
04847    prune_mappings();
04848    mark_peers();
04849    prune_peers();
04850 
04851    return 0;
04852 }

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3558 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, dr, and dundi_request::list.

Referenced by dundi_lookup_internal().

03559 {
03560    AST_LIST_LOCK(&peers);
03561    AST_LIST_REMOVE(&requests, dr, list);
03562    AST_LIST_UNLOCK(&peers);
03563 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1275 of file pbx_dundi.c.

References ast_aes_decrypt_key, ast_aes_encrypt_key, ast_encrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), ast_sign_bin, build_iv(), dundi_eid_to_str(), dundi_peer::eid, dundi_peer::inkey, dundi_peer::keyexpire, LOG_NOTICE, dundi_peer::outkey, dundi_peer::sentfullkey, dundi_peer::txenckey, dundi_peer::us_dcx, dundi_peer::us_ecx, and dundi_peer::us_keycrc32.

Referenced by dundi_encrypt().

01276 {
01277    unsigned char key[16];
01278    struct ast_key *ekey, *skey;
01279    char eid_str[20];
01280    int res;
01281    if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
01282       build_iv(key);
01283       ast_aes_encrypt_key(key, &peer->us_ecx);
01284       ast_aes_decrypt_key(key, &peer->us_dcx);
01285       ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01286       if (!ekey) {
01287          ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
01288             peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01289          return -1;
01290       }
01291       skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01292       if (!skey) {
01293          ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
01294             peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01295          return -1;
01296       }
01297       if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
01298          ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
01299          return -1;
01300       }
01301       if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
01302          ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
01303          return -1;
01304       }
01305       peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
01306       peer->sentfullkey = 0;
01307       /* Looks good */
01308       time(&peer->keyexpire);
01309       peer->keyexpire += dundi_key_ttl;
01310    }
01311    return 0;
01312 }


Variable Documentation

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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4921 of file pbx_dundi.c.

struct dundi_peer* any_peer [static]

Wildcard peer.

This peer is created if the [*] entry is specified in dundi.conf

Definition at line 266 of file pbx_dundi.c.

Referenced by find_peer(), handle_command_response(), and set_config().

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4921 of file pbx_dundi.c.

int authdebug = 0 [static]

Definition at line 107 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 104 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2904 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_dundi_do_debug_deprecated = { .handler = dundi_do_debug_deprecated , .summary = "Enable/Disable DUNDi debugging" ,__VA_ARGS__ } [static]

Definition at line 2902 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi_do_store_history_deprecated = { .handler = dundi_do_store_history_deprecated , .summary = "Enable/Disable DUNDi historic records" ,__VA_ARGS__ } [static]

Definition at line 2903 of file pbx_dundi.c.

char country[80] [static]

Definition at line 119 of file pbx_dundi.c.

Referenced by ind_load_module(), and SendDialTone().

char cursecret[80] [static]

Definition at line 123 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 113 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 115 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 110 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 109 of file pbx_dundi.c.

struct ast_custom_function dundi_query_function [static]

Definition at line 4067 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

struct ast_app_option dundi_query_opts[128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, } [static]

Definition at line 3973 of file pbx_dundi.c.

Referenced by dundi_query_read().

struct ast_datastore_info dundi_result_datastore_info [static]

Initial value:

 {
   .type = "DUNDIQUERY",
   .destroy = drds_destroy_cb,
}

Definition at line 3994 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundi_result_read().

struct ast_custom_function dundi_result_function [static]

Definition at line 4153 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

unsigned int dundi_result_id

Definition at line 3975 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 127 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4668 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 108 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 106 of file pbx_dundi.c.

char email[80] [static]

Definition at line 120 of file pbx_dundi.c.

dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } } [static]

Definition at line 126 of file pbx_dundi.c.

Referenced by find_peer(), and set_config().

int global_autokilltimeout = 0 [static]

Definition at line 111 of file pbx_dundi.c.

dundi_eid global_eid [static]

Definition at line 112 of file pbx_dundi.c.

Referenced by build_peer(), dundi_show_entityid(), reset_global_eid(), and set_config().

int global_storehistory = 0 [static]

Definition at line 114 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 99 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 124 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 117 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 101 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 102 of file pbx_dundi.c.

char org[80] [static]

Definition at line 116 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 121 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 103 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 125 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 100 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 122 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 118 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 105 of file pbx_dundi.c.


Generated on Thu Jul 9 13:41:28 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7