Fri Jun 19 12:10:45 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 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct dundi_peerany_peer
 Wildcard peer.
static struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 0
static pthread_t clearcachethreadid = AST_PTHREADT_NULL
static struct ast_cli_entry cli_dundi []
static 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 4212 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 3923 of file pbx_dundi.c.

03923      {
03924    OPT_BYPASS_CACHE = (1 << 0),
03925 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4879 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4879 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3414 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03415 {
03416    struct dundi_transaction *trans;
03417 
03418    AST_LIST_LOCK(&peers);
03419    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03420       /* This will remove the transaction from the list */
03421       destroy_trans(trans, 0);
03422    }
03423    AST_LIST_UNLOCK(&peers);
03424 }

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

Definition at line 1916 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), AST_SCHED_DEL, dundi_transaction::autokillid, destroy_packet(), destroy_packets(), dundi_packet::h, dundi_transaction::lasttrans, dundi_packet::list, LOG_WARNING, dundi_hdr::oseqno, dundi_transaction::packets, and sched.

Referenced by handle_frame().

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

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

Definition at line 4199 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

04200 {
04201    struct permission *perm;
04202 
04203    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04204       return;
04205 
04206    strcpy(perm->name, s);
04207    perm->allow = allow;
04208 
04209    AST_LIST_INSERT_TAIL(permlist, perm, list);
04210 }

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

Definition at line 3369 of file pbx_dundi.c.

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

Referenced by build_transactions().

03370 {
03371    struct dundi_transaction *trans;
03372    int x;
03373    char eid_str[20];
03374    char eid_str2[20];
03375 
03376    /* Ignore if not registered */
03377    if (!p->addr.sin_addr.s_addr)
03378       return 0;
03379    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03380       return 0;
03381 
03382    if (ast_strlen_zero(dr->number))
03383       ast_debug(1, "Will query peer '%s' for '%s' (context '%s')\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
03384    else
03385       ast_debug(1, "Will query peer '%s' for '%s@%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
03386 
03387    trans = create_transaction(p);
03388    if (!trans)
03389       return -1;
03390    trans->parent = dr;
03391    trans->ttl = ttl;
03392    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03393       trans->eids[x] = *avoid[x];
03394    trans->eidcount = x;
03395    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03396    
03397    return 0;
03398 }

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

Definition at line 1195 of file pbx_dundi.c.

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

Referenced by create_transaction().

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

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

Definition at line 3535 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03536 {
03537    /* Idea is that we're calculating a checksum which is independent of
03538       the order that the EID's are listed in */
03539    uint32_t acrc32 = 0;
03540    int x;
03541    for (x=0;avoid[x];x++) {
03542       /* Order doesn't matter */
03543       if (avoid[x+1]) {
03544          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03545       }
03546    }
03547    return acrc32;
03548 }

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

Definition at line 445 of file pbx_dundi.c.

References ast_random().

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

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

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

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

04215 {
04216    char *t, *fields[MAX_OPTS];
04217    struct dundi_mapping *map;
04218    int x;
04219    int y;
04220 
04221    t = ast_strdupa(value);
04222       
04223    AST_LIST_TRAVERSE(&mappings, map, list) {
04224       /* Find a double match */
04225       if (!strcasecmp(map->dcontext, name) && 
04226          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
04227            (!value[strlen(map->lcontext)] || 
04228             (value[strlen(map->lcontext)] == ','))))
04229          break;
04230    }
04231    if (!map) {
04232       if (!(map = ast_calloc(1, sizeof(*map))))
04233          return;
04234       AST_LIST_INSERT_HEAD(&mappings, map, list);
04235       map->dead = 1;
04236    }
04237    map->options = 0;
04238    memset(fields, 0, sizeof(fields));
04239    x = 0;
04240    while (t && x < MAX_OPTS) {
04241       fields[x++] = t;
04242       t = strchr(t, ',');
04243       if (t) {
04244          *t = '\0';
04245          t++;
04246       }
04247    } /* Russell was here, arrrr! */
04248    if ((x == 1) && ast_strlen_zero(fields[0])) {
04249       /* Placeholder mapping */
04250       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04251       map->dead = 0;
04252    } else if (x >= 4) {
04253       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04254       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04255       if ((sscanf(fields[1], "%d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) {
04256          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04257          if ((map->tech = str2tech(fields[2])))
04258             map->dead = 0;
04259       } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') {
04260          map->weightstr = ast_strdup(fields[1]);
04261          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04262          if ((map->tech = str2tech(fields[2])))
04263             map->dead = 0;
04264       } else {
04265          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04266       }
04267       for (y = 4;y < x; y++) {
04268          if (!strcasecmp(fields[y], "nounsolicited"))
04269             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04270          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04271             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04272          else if (!strcasecmp(fields[y], "residential"))
04273             map->options |= DUNDI_FLAG_RESIDENTIAL;
04274          else if (!strcasecmp(fields[y], "commercial"))
04275             map->options |= DUNDI_FLAG_COMMERCIAL;
04276          else if (!strcasecmp(fields[y], "mobile"))
04277             map->options |= DUNDI_FLAG_MOBILE;
04278          else if (!strcasecmp(fields[y], "nopartial"))
04279             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04280          else
04281             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04282       }
04283    } else 
04284       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04285 }

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

Definition at line 4369 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_eid_cmp(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_SCHED_DEL, dundi_peer::dead, destroy_permissions(), 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.

04370 {
04371    struct dundi_peer *peer;
04372    struct ast_hostent he;
04373    struct hostent *hp;
04374    dundi_eid testeid;
04375    int needregister=0;
04376    char eid_str[20];
04377 
04378    AST_LIST_LOCK(&peers);
04379    AST_LIST_TRAVERSE(&peers, peer, list) {
04380       if (!ast_eid_cmp(&peer->eid, eid)) {   
04381          break;
04382       }
04383    }
04384    if (!peer) {
04385       /* Add us into the list */
04386       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04387          AST_LIST_UNLOCK(&peers);
04388          return;
04389       }
04390       peer->registerid = -1;
04391       peer->registerexpire = -1;
04392       peer->qualifyid = -1;
04393       peer->addr.sin_family = AF_INET;
04394       peer->addr.sin_port = htons(DUNDI_PORT);
04395       populate_addr(peer, eid);
04396       AST_LIST_INSERT_HEAD(&peers, peer, list);
04397    }
04398    peer->dead = 0;
04399    peer->eid = *eid;
04400    peer->us_eid = global_eid;
04401    destroy_permissions(&peer->permit);
04402    destroy_permissions(&peer->include);
04403    AST_SCHED_DEL(sched, peer->registerid);
04404    for (; v; v = v->next) {
04405       if (!strcasecmp(v->name, "inkey")) {
04406          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04407       } else if (!strcasecmp(v->name, "outkey")) {
04408          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04409       } else if (!strcasecmp(v->name, "host")) {
04410          if (!strcasecmp(v->value, "dynamic")) {
04411             peer->dynamic = 1;
04412          } else {
04413             hp = ast_gethostbyname(v->value, &he);
04414             if (hp) {
04415                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04416                peer->dynamic = 0;
04417             } else {
04418                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04419                peer->dead = 1;
04420             }
04421          }
04422       } else if (!strcasecmp(v->name, "ustothem")) {
04423          if (!ast_str_to_eid(&testeid, v->value))
04424             peer->us_eid = testeid;
04425          else
04426             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04427       } else if (!strcasecmp(v->name, "include")) {
04428          append_permission(&peer->include, v->value, 1);
04429       } else if (!strcasecmp(v->name, "permit")) {
04430          append_permission(&peer->permit, v->value, 1);
04431       } else if (!strcasecmp(v->name, "noinclude")) {
04432          append_permission(&peer->include, v->value, 0);
04433       } else if (!strcasecmp(v->name, "deny")) {
04434          append_permission(&peer->permit, v->value, 0);
04435       } else if (!strcasecmp(v->name, "register")) {
04436          needregister = ast_true(v->value);
04437       } else if (!strcasecmp(v->name, "order")) {
04438          if (!strcasecmp(v->value, "primary"))
04439             peer->order = 0;
04440          else if (!strcasecmp(v->value, "secondary"))
04441             peer->order = 1;
04442          else if (!strcasecmp(v->value, "tertiary"))
04443             peer->order = 2;
04444          else if (!strcasecmp(v->value, "quartiary"))
04445             peer->order = 3;
04446          else {
04447             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);
04448          }
04449       } else if (!strcasecmp(v->name, "qualify")) {
04450          if (!strcasecmp(v->value, "no")) {
04451             peer->maxms = 0;
04452          } else if (!strcasecmp(v->value, "yes")) {
04453             peer->maxms = DEFAULT_MAXMS;
04454          } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
04455             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04456                ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04457             peer->maxms = 0;
04458          }
04459       } else if (!strcasecmp(v->name, "model")) {
04460          if (!strcasecmp(v->value, "inbound"))
04461             peer->model = DUNDI_MODEL_INBOUND;
04462          else if (!strcasecmp(v->value, "outbound")) 
04463             peer->model = DUNDI_MODEL_OUTBOUND;
04464          else if (!strcasecmp(v->value, "symmetric"))
04465             peer->model = DUNDI_MODEL_SYMMETRIC;
04466          else if (!strcasecmp(v->value, "none"))
04467             peer->model = 0;
04468          else {
04469             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04470                v->value, v->lineno);
04471          }
04472       } else if (!strcasecmp(v->name, "precache")) {
04473          if (!strcasecmp(v->value, "inbound"))
04474             peer->pcmodel = DUNDI_MODEL_INBOUND;
04475          else if (!strcasecmp(v->value, "outbound")) 
04476             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04477          else if (!strcasecmp(v->value, "symmetric"))
04478             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04479          else if (!strcasecmp(v->value, "none"))
04480             peer->pcmodel = 0;
04481          else {
04482             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04483                v->value, v->lineno);
04484          }
04485       }
04486    }
04487    (*globalpcmode) |= peer->pcmodel;
04488    if (!peer->model && !peer->pcmodel) {
04489       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04490          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04491       peer->dead = 1;
04492    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04493       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04494          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04495       peer->dead = 1;
04496    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04497       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04498          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04499       peer->dead = 1;
04500    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04501       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04502          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04503    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04504       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", 
04505          ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04506    } else { 
04507       if (needregister) {
04508          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04509       }
04510       qualify_peer(peer, 1);
04511    }
04512    AST_LIST_UNLOCK(&peers);
04513 }

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

Definition at line 2006 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

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

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

Definition at line 3426 of file pbx_dundi.c.

References append_transaction(), ast_clear_flag_nonstd, ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, cache_lookup(), dr, 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().

03427 {
03428    struct dundi_peer *p;
03429    int x;
03430    int res;
03431    int pass;
03432    int allowconnect;
03433    char eid_str[20];
03434    AST_LIST_LOCK(&peers);
03435    AST_LIST_TRAVERSE(&peers, p, list) {
03436       if (modeselect == 1) {
03437          /* Send the precache to push upstreams only! */
03438          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03439          allowconnect = 1;
03440       } else {
03441          /* Normal lookup / EID query */
03442          pass = has_permission(&p->include, dr->dcontext);
03443          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03444       }
03445       if (skip) {
03446          if (!ast_eid_cmp(skip, &p->eid))
03447             pass = 0;
03448       }
03449       if (pass) {
03450          if (p->order <= order) {
03451             /* Check order first, then check cache, regardless of
03452                omissions, this gets us more likely to not have an
03453                affected answer. */
03454             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03455                res = 0;
03456                /* Make sure we haven't already seen it and that it won't
03457                   affect our answer */
03458                for (x=0;avoid[x];x++) {
03459                   if (!ast_eid_cmp(avoid[x], &p->eid) || !ast_eid_cmp(avoid[x], &p->us_eid)) {
03460                      /* If not a direct connection, it affects our answer */
03461                      if (directs && !directs[x]) 
03462                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03463                      break;
03464                   }
03465                }
03466                /* Make sure we can ask */
03467                if (allowconnect) {
03468                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03469                      /* Check for a matching or 0 cache entry */
03470                      append_transaction(dr, p, ttl, avoid);
03471                   } else {
03472                      ast_debug(1, "Avoiding '%s' in transaction\n", ast_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03473                   }
03474                }
03475             }
03476             *foundcache |= res;
03477          } else if (!*skipped || (p->order < *skipped))
03478             *skipped = p->order;
03479       }
03480    }
03481    AST_LIST_UNLOCK(&peers);
03482 }

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

Definition at line 1143 of file pbx_dundi.c.

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

Referenced by build_transactions().

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

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

Definition at line 1071 of file pbx_dundi.c.

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

Referenced by cache_lookup().

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

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

Definition at line 800 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 765 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3400 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03401 {
03402    struct dundi_transaction *trans;
03403 
03404    AST_LIST_LOCK(&peers);
03405    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03406       /* Orphan transaction from request */
03407       trans->parent = NULL;
03408       /* Send final cancel */
03409       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03410    }
03411    AST_LIST_UNLOCK(&peers);
03412 }

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

Definition at line 1394 of file pbx_dundi.c.

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

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

static void check_password ( void   )  [static]

Definition at line 2073 of file pbx_dundi.c.

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

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

static int check_request ( struct dundi_request dr  )  [static]

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

03522 {
03523    struct dundi_request *cur;
03524 
03525    AST_LIST_LOCK(&peers);
03526    AST_LIST_TRAVERSE(&requests, cur, list) {
03527       if (cur == dr)
03528          break;
03529    }
03530    AST_LIST_UNLOCK(&peers);
03531    
03532    return cur ? 1 : 0;
03533 }

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

Definition at line 2357 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

02358 {
02359    int which=0, len;
02360    char *ret = NULL;
02361    struct dundi_peer *p;
02362    char eid_str[20];
02363 
02364    if (pos != rpos)
02365       return NULL;
02366    AST_LIST_LOCK(&peers);
02367    len = strlen(word);
02368    AST_LIST_TRAVERSE(&peers, p, list) {
02369       const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02370       if (!strncasecmp(word, s, len) && ++which > state) {
02371          ret = ast_strdup(s);
02372          break;
02373       }
02374    }
02375    AST_LIST_UNLOCK(&peers);
02376    return ret;
02377 }

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

Definition at line 2876 of file pbx_dundi.c.

References dundi_peer::addr, 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().

02877 {
02878    struct dundi_transaction *trans;
02879    int tid;
02880    
02881    /* Don't allow creation of transactions to non-registered peers */
02882    if (p && !p->addr.sin_addr.s_addr)
02883       return NULL;
02884    tid = get_trans_id();
02885    if (tid < 1)
02886       return NULL;
02887    if (!(trans = ast_calloc(1, sizeof(*trans))))
02888       return NULL;
02889 
02890    if (global_storehistory) {
02891       trans->start = ast_tvnow();
02892       ast_set_flag(trans, FLAG_STOREHIST);
02893    }
02894    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02895    trans->autokillid = -1;
02896    if (p) {
02897       apply_peer(trans, p);
02898       if (!p->sentfullkey)
02899          ast_set_flag(trans, FLAG_SENDFULLKEY);
02900    }
02901    trans->strans = tid;
02902    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02903    
02904    return trans;
02905 }

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

Definition at line 1286 of file pbx_dundi.c.

References ast_aes_decrypt.

Referenced by dundi_decrypt().

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

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

Definition at line 1447 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4162 of file pbx_dundi.c.

References ast_free, and map.

Referenced by prune_mappings().

04163 {
04164    if (map->weightstr)
04165       ast_free(map->weightstr);
04166    ast_free(map);
04167 }

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

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

02924 {
02925    if (pack->parent)
02926       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02927    AST_SCHED_DEL(sched, pack->retransid);
02928    if (needfree)
02929       ast_free(pack);
02930 }

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

Definition at line 1905 of file pbx_dundi.c.

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

Referenced by ack_trans(), and handle_frame().

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

static void destroy_peer ( struct dundi_peer peer  )  [static]

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

04152 {
04153    AST_SCHED_DEL(sched, peer->registerid);
04154    if (peer->regtrans)
04155       destroy_trans(peer->regtrans, 0);
04156    AST_SCHED_DEL(sched, peer->qualifyid);
04157    destroy_permissions(&peer->permit);
04158    destroy_permissions(&peer->include);
04159    ast_free(peer);
04160 }

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

Definition at line 4143 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, and permission::list.

Referenced by build_peer(), and destroy_peer().

04144 {
04145    struct permission *perm;
04146 
04147    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04148       ast_free(perm);
04149 }

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

Definition at line 2932 of file pbx_dundi.c.

References ast_eid_cmp(), ast_eid_to_str(), 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_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().

02933 {
02934    struct dundi_peer *peer;
02935    int ms;
02936    int x;
02937    int cnt;
02938    char eid_str[20];
02939    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02940       AST_LIST_TRAVERSE(&peers, peer, list) {
02941          if (peer->regtrans == trans)
02942             peer->regtrans = NULL;
02943          if (peer->qualtrans == trans) {
02944             if (fromtimeout) {
02945                if (peer->lastms > -1)
02946                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02947                peer->lastms = -1;
02948             } else {
02949                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02950                if (ms < 1)
02951                   ms = 1;
02952                if (ms < peer->maxms) {
02953                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02954                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02955                } else if (peer->lastms < peer->maxms) {
02956                   ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
02957                }
02958                peer->lastms = ms;
02959             }
02960             peer->qualtrans = NULL;
02961          }
02962          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02963             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02964                if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) {
02965                   peer->avgms = 0;
02966                   cnt = 0;
02967                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02968                      ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02969                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02970                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02971                      peer->lookups[x] = peer->lookups[x-1];
02972                      if (peer->lookups[x]) {
02973                         peer->avgms += peer->lookuptimes[x];
02974                         cnt++;
02975                      }
02976                   }
02977                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
02978                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
02979                   if (peer->lookups[0]) {
02980                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
02981                      peer->avgms += peer->lookuptimes[0];
02982                      cnt++;
02983                   }
02984                   if (cnt)
02985                      peer->avgms /= cnt;
02986                }
02987             }
02988          }
02989       }
02990    }
02991    if (trans->parent) {
02992       /* Unlink from parent if appropriate */
02993       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
02994       if (AST_LIST_EMPTY(&trans->parent->trans)) {
02995          /* Wake up sleeper */
02996          if (trans->parent->pfds[1] > -1) {
02997             if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
02998                ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02999             }
03000          }
03001       }
03002    }
03003    /* Unlink from all trans */
03004    AST_LIST_REMOVE(&alltrans, trans, all);
03005    destroy_packets(&trans->packets);
03006    destroy_packets(&trans->lasttrans);
03007    AST_SCHED_DEL(sched, trans->autokillid);
03008    if (trans->thread) {
03009       /* If used by a thread, mark as dead and be done */
03010       ast_set_flag(trans, FLAG_DEAD);
03011    } else
03012       ast_free(trans);
03013 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3254 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03255 {
03256    struct dundi_transaction *trans;
03257    AST_LIST_LOCK(&peers);
03258    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03259       dundi_discover(trans);
03260    }
03261    AST_LIST_UNLOCK(&peers);
03262    return 0;
03263 }

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

Definition at line 3109 of file pbx_dundi.c.

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

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

03110 {
03111    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03112    char eid_str[20];
03113    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03114       ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03115    trans->autokillid = -1;
03116    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03117    return 0;
03118 }

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

Definition at line 4314 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04315 {
04316    struct dundi_peer *peer = (struct dundi_peer *)data;
04317    peer->qualifyid = -1;
04318    qualify_peer(peer, 0);
04319    return 0;
04320 }

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

Definition at line 4288 of file pbx_dundi.c.

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

04289 {
04290    struct dundi_ie_data ied;
04291    struct dundi_peer *peer = (struct dundi_peer *)data;
04292    char eid_str[20];
04293    char eid_str2[20];
04294    ast_debug(1, "Register us as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
04295    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04296    /* Destroy old transaction if there is one */
04297    if (peer->regtrans)
04298       destroy_trans(peer->regtrans, 0);
04299    peer->regtrans = create_transaction(peer);
04300    if (peer->regtrans) {
04301       ast_set_flag(peer->regtrans, FLAG_ISREG);
04302       memset(&ied, 0, sizeof(ied));
04303       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04304       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04305       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04306       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04307       
04308    } else
04309       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04310 
04311    return 0;
04312 }

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

Note:
Called with the peers list already locked

Definition at line 1220 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3939 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03940 {
03941    ast_free(drds);
03942 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3944 of file pbx_dundi.c.

References drds_destroy().

03945 {
03946    struct dundi_result_datastore *drds = data;
03947    drds_destroy(drds);
03948 }

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

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

Referenced by handle_command_response().

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

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

Definition at line 988 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, dundi_ies::called_context, dundi_query_state::called_context, dundi_ies::called_number, dundi_query_state::called_number, dundi_ies::cbypass, dundi_mapping::dcontext, dundi_query_state::directs, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_DPRESPONSE, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_lookup_thread(), dundi_send(), dundi_ies::eid_direct, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_query_state::fluffy, dundi_mapping::list, 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, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

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

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

Definition at line 4559 of file pbx_dundi.c.

References chan, DUNDI_FLAG_CANMATCH, and dundi_helper().

04560 {
04561    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04562 }

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

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

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

03143 {
03144    struct dundi_ie_data ied;
03145    int x;
03146    if (!trans->parent) {
03147       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03148       return -1;
03149    }
03150    memset(&ied, 0, sizeof(ied));
03151    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03152    if (!dundi_eid_zero(&trans->us_eid))
03153       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03154    for (x=0;x<trans->eidcount;x++)
03155       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03156    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03157    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03158    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03159    if (trans->parent->cbypass)
03160       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03161    if (trans->autokilltimeout)
03162       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03163    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03164 }

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

Definition at line 2195 of file pbx_dundi.c.

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

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

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

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

02397 {
02398    int res;
02399    char tmp[256];
02400    char fs[80] = "";
02401    char *context;
02402    int x;
02403    int bypass = 0;
02404    struct dundi_result dr[MAX_RESULTS];
02405    struct timeval start;
02406    switch (cmd) {
02407    case CLI_INIT:
02408       e->command = "dundi lookup";
02409       e->usage =
02410          "Usage: dundi lookup <number>[@context] [bypass]\n"
02411          "       Lookup the given number within the given DUNDi context\n"
02412          "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
02413          "keyword is specified.\n";
02414       return NULL;
02415    case CLI_GENERATE:
02416       return NULL;
02417    }
02418 
02419    if ((a->argc < 3) || (a->argc > 4))
02420       return CLI_SHOWUSAGE;
02421    if (a->argc > 3) {
02422       if (!strcasecmp(a->argv[3], "bypass"))
02423          bypass=1;
02424       else
02425          return CLI_SHOWUSAGE;
02426    }
02427    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02428    context = strchr(tmp, '@');
02429    if (context) {
02430       *context = '\0';
02431       context++;
02432    }
02433    start = ast_tvnow();
02434    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02435    
02436    if (res < 0) 
02437       ast_cli(a->fd, "DUNDi lookup returned error.\n");
02438    else if (!res) 
02439       ast_cli(a->fd, "DUNDi lookup returned no results.\n");
02440    else
02441       sort_results(dr, res);
02442    for (x=0;x<res;x++) {
02443       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));
02444       ast_cli(a->fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02445    }
02446    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02447    return CLI_SUCCESS;
02448 }

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

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

02451 {
02452    int res;
02453    char tmp[256];
02454    char *context;
02455    struct timeval start;
02456    switch (cmd) {
02457    case CLI_INIT:
02458       e->command = "dundi precache";
02459       e->usage = 
02460          "Usage: dundi precache <number>[@context]\n"
02461          "       Lookup the given number within the given DUNDi context\n"
02462          "(or e164 if none is specified) and precaches the results to any\n"
02463          "upstream DUNDi push servers.\n";
02464       return NULL;
02465    case CLI_GENERATE:
02466       return NULL;
02467    }
02468    if ((a->argc < 3) || (a->argc > 3))
02469       return CLI_SHOWUSAGE;
02470    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02471    context = strchr(tmp, '@');
02472    if (context) {
02473       *context = '\0';
02474       context++;
02475    }
02476    start = ast_tvnow();
02477    res = dundi_precache(context, tmp);
02478    
02479    if (res < 0) 
02480       ast_cli(a->fd, "DUNDi precache returned error.\n");
02481    else if (!res) 
02482       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02483    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02484    return CLI_SUCCESS;
02485 }

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

Definition at line 2487 of file pbx_dundi.c.

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

02488 {
02489    int res;
02490    char tmp[256];
02491    char *context;
02492    dundi_eid eid;
02493    struct dundi_entity_info dei;
02494    switch (cmd) {
02495    case CLI_INIT:
02496       e->command = "dundi query";
02497       e->usage = 
02498          "Usage: dundi query <entity>[@context]\n"
02499          "       Attempts to retrieve contact information for a specific\n"
02500          "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
02501          "e164 if none is specified).\n";
02502       return NULL;
02503    case CLI_GENERATE:
02504       return NULL;
02505    }
02506    if ((a->argc < 3) || (a->argc > 3))
02507       return CLI_SHOWUSAGE;
02508    if (ast_str_to_eid(&eid, a->argv[2])) {
02509       ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
02510       return CLI_SHOWUSAGE;
02511    }
02512    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02513    context = strchr(tmp, '@');
02514    if (context) {
02515       *context = '\0';
02516       context++;
02517    }
02518    res = dundi_query_eid(&dei, context, eid);
02519    if (res < 0) 
02520       ast_cli(a->fd, "DUNDi Query EID returned error.\n");
02521    else if (!res) 
02522       ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
02523    else {
02524       ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
02525       ast_cli(a->fd, "Department:      %s\n", dei.orgunit);
02526       ast_cli(a->fd, "Organization:    %s\n", dei.org);
02527       ast_cli(a->fd, "City/Locality:   %s\n", dei.locality);
02528       ast_cli(a->fd, "State/Province:  %s\n", dei.stateprov);
02529       ast_cli(a->fd, "Country:         %s\n", dei.country);
02530       ast_cli(a->fd, "E-mail:          %s\n", dei.email);
02531       ast_cli(a->fd, "Phone:           %s\n", dei.phone);
02532       ast_cli(a->fd, "IP Address:      %s\n", dei.ipaddr);
02533    }
02534    return CLI_SUCCESS;
02535 }

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

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

02246 {
02247    switch (cmd) {
02248    case CLI_INIT:
02249       e->command = "dundi [no] store history";
02250       e->usage = 
02251          "Usage: dundi [no] store history\n"
02252          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02253          "purposes\n";
02254       return NULL;
02255    case CLI_GENERATE:
02256       return NULL;
02257    }
02258    if (a->argc < 3 || a->argc > 4)
02259       return CLI_SHOWUSAGE;
02260    
02261    if (a->argc == 3) {
02262       global_storehistory = 1;
02263       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02264    } else {
02265       global_storehistory = 0;
02266       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02267    }
02268    return CLI_SUCCESS;
02269 }

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

Definition at line 1327 of file pbx_dundi.c.

References ast_debug, ast_log(), ast_set_flag, ast_test_flag, 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().

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

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

Definition at line 276 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

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

04565 {
04566    struct dundi_result results[MAX_RESULTS];
04567    int res;
04568    int x=0;
04569    char req[1024];
04570    const char *dundiargs;
04571    struct ast_app *dial;
04572    
04573    if (!strncasecmp(context, "macro-", 6)) {
04574       if (!chan) {   
04575          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04576          return -1;
04577       }
04578       /* If done as a macro, use macro extension */
04579       if (!strcasecmp(exten, "s")) {
04580          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04581          if (ast_strlen_zero(exten))
04582             exten = chan->macroexten;
04583          if (ast_strlen_zero(exten))
04584             exten = chan->exten;
04585          if (ast_strlen_zero(exten)) { 
04586             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04587             return -1;
04588          }
04589       }
04590       if (ast_strlen_zero(data))
04591          data = "e164";
04592    } else {
04593       if (ast_strlen_zero(data))
04594          data = context;
04595    }
04596    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04597    if (res > 0) {
04598       sort_results(results, res);
04599       for (x=0;x<res;x++) {
04600          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04601             if (!--priority)
04602                break;
04603          }
04604       }
04605    }
04606    if (x < res) {
04607       /* Got a hit! */
04608       dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
04609       snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest, 
04610          S_OR(dundiargs, ""));
04611       dial = pbx_findapp("Dial");
04612       if (dial)
04613          res = pbx_exec(chan, dial, req);
04614    } else
04615       res = -1;
04616    return res;
04617 }

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

References chan, DUNDI_FLAG_EXISTS, and dundi_helper().

04555 {
04556    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04557 }

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

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

02299 {
02300    int stats = 0;
02301    switch (cmd) {
02302    case CLI_INIT:
02303       e->command = "dundi flush [stats]";
02304       e->usage = 
02305          "Usage: dundi flush [stats]\n"
02306          "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
02307          "'stats' is present, clears timer statistics instead of normal\n"
02308          "operation.\n";
02309       return NULL;
02310    case CLI_GENERATE:
02311       return NULL;
02312    }
02313    if ((a->argc < 2) || (a->argc > 3))
02314       return CLI_SHOWUSAGE;
02315    if (a->argc > 2) {
02316       if (!strcasecmp(a->argv[2], "stats"))
02317          stats = 1;
02318       else
02319          return CLI_SHOWUSAGE;
02320    }
02321    if (stats) {
02322       /* Flush statistics */
02323       struct dundi_peer *p;
02324       int x;
02325       AST_LIST_LOCK(&peers);
02326       AST_LIST_TRAVERSE(&peers, p, list) {
02327          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02328             if (p->lookups[x])
02329                ast_free(p->lookups[x]);
02330             p->lookups[x] = NULL;
02331             p->lookuptimes[x] = 0;
02332          }
02333          p->avgms = 0;
02334       }
02335       AST_LIST_UNLOCK(&peers);
02336    } else {
02337       ast_db_deltree("dundi/cache", NULL);
02338       ast_cli(a->fd, "DUNDi Cache Flushed\n");
02339    }
02340    return CLI_SUCCESS;
02341 }

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

04516 {
04517    struct dundi_result results[MAX_RESULTS];
04518    int res;
04519    int x;
04520    int found = 0;
04521    if (!strncasecmp(context, "macro-", 6)) {
04522       if (!chan) {   
04523          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04524          return -1;
04525       }
04526       /* If done as a macro, use macro extension */
04527       if (!strcasecmp(exten, "s")) {
04528          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04529          if (ast_strlen_zero(exten))
04530             exten = chan->macroexten;
04531          if (ast_strlen_zero(exten))
04532             exten = chan->exten;
04533          if (ast_strlen_zero(exten)) { 
04534             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04535             return -1;
04536          }
04537       }
04538       if (ast_strlen_zero(data))
04539          data = "e164";
04540    } else {
04541       if (ast_strlen_zero(data))
04542          data = context;
04543    }
04544    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04545    for (x=0;x<res;x++) {
04546       if (ast_test_flag(results + x, flag))
04547          found++;
04548    }
04549    if (found >= priority)
04550       return 1;
04551    return 0;
04552 }

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

Definition at line 3120 of file pbx_dundi.c.

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

Referenced by dundi_discover().

03121 {
03122    struct dundi_peer *p;
03123    if (!ast_eid_cmp(eid, us)) {
03124       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03125       return;
03126    }
03127    AST_LIST_LOCK(&peers);
03128    AST_LIST_TRAVERSE(&peers, p, list) {
03129       if (!ast_eid_cmp(&p->eid, eid)) {
03130          if (has_permission(&p->include, context))
03131             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03132          else
03133             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03134          break;
03135       }
03136    }
03137    if (!p)
03138       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03139    AST_LIST_UNLOCK(&peers);
03140 }

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

03653 {
03654    struct dundi_hint_metadata hmd;
03655    dundi_eid *avoid[1] = { NULL, };
03656    int direct[1] = { 0, };
03657    int expiration = dundi_cache_time;
03658    memset(&hmd, 0, sizeof(hmd));
03659    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03660    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03661 }

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

References abort_request(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), chan, check_request(), discover_transactions(), dr, 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().

03551 {
03552    int res;
03553    struct dundi_request dr, *pending;
03554    dundi_eid *rooteid=NULL;
03555    int x;
03556    int ttlms;
03557    int ms;
03558    int foundcache;
03559    int skipped=0;
03560    int order=0;
03561    char eid_str[20];
03562    struct timeval start;
03563    
03564    /* Don't do anthing for a hungup channel */
03565    if (chan && ast_check_hangup(chan))
03566       return 0;
03567 
03568    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03569 
03570    for (x=0;avoid[x];x++)
03571       rooteid = avoid[x];
03572    /* Now perform real check */
03573    memset(&dr, 0, sizeof(dr));
03574    if (pipe(dr.pfds)) {
03575       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03576       return -1;
03577    }
03578    dr.dr = result;
03579    dr.hmd = hmd;
03580    dr.maxcount = maxret;
03581    dr.expiration = *expiration;
03582    dr.cbypass = cbypass;
03583    dr.crc32 = avoid_crc32(avoid);
03584    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03585    ast_copy_string(dr.number, number, sizeof(dr.number));
03586    if (rooteid)
03587       dr.root_eid = *rooteid;
03588    res = register_request(&dr, &pending);
03589    if (res) {
03590       /* Already a request */
03591       if (rooteid && !ast_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03592          /* This is on behalf of someone else.  Go ahead and close this out since
03593             they'll get their answer anyway. */
03594          ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03595             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03596          close(dr.pfds[0]);
03597          close(dr.pfds[1]);
03598          return -2;
03599       } else {
03600          /* Wait for the cache to populate */
03601          ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n",
03602             dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03603          start = ast_tvnow();
03604          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03605             /* XXX Would be nice to have a way to poll/select here XXX */
03606             /* XXX this is a busy wait loop!!! */
03607             usleep(1);
03608          }
03609          /* Continue on as normal, our cache should kick in */
03610       }
03611    }
03612    /* Create transactions */
03613    do {
03614       order = skipped;
03615       skipped = 0;
03616       foundcache = 0;
03617       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03618    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03619    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03620       do this earlier because we didn't know if we were going to have transactions
03621       or not. */
03622    if (!ttl) {
03623       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03624       abort_request(&dr);
03625       unregister_request(&dr);
03626       close(dr.pfds[0]);
03627       close(dr.pfds[1]);
03628       return 0;
03629    }
03630       
03631    /* Optimize transactions */
03632    optimize_transactions(&dr, order);
03633    /* Actually perform transactions */
03634    discover_transactions(&dr);
03635    /* Wait for transaction to come back */
03636    start = ast_tvnow();
03637    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
03638       ms = 100;
03639       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03640    }
03641    if (chan && ast_check_hangup(chan))
03642       ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03643    cancel_request(&dr);
03644    unregister_request(&dr);
03645    res = dr.respcount;
03646    *expiration = dr.expiration;
03647    close(dr.pfds[0]);
03648    close(dr.pfds[1]);
03649    return res;
03650 }

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

Definition at line 485 of file pbx_dundi.c.

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_eid_to_str(), ast_exists_extension(), AST_FLAGS_ALL, ast_ignore_pattern(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_var_delete(), dr, 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().

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

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

Definition at line 558 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), dundi_query_state::directs, dr, DUNDI_CAUSE_DUPLICATE, DUNDI_COMMAND_DPRESPONSE, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_cause(), dundi_ie_append_hint(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_query_state::eids, 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().

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

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

Definition at line 4619 of file pbx_dundi.c.

References chan, DUNDI_FLAG_MATCHMORE, and dundi_helper().

04620 {
04621    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04622 }

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

Pre-cache to push upstream peers.

Definition at line 3796 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03797 {
03798    dundi_eid *avoid[1] = { NULL, };
03799    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03800 }

static void dundi_precache_full ( void   )  [static]

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

03700 {
03701    struct dundi_mapping *cur;
03702    struct ast_context *con;
03703    struct ast_exten *e;
03704 
03705    AST_LIST_TRAVERSE(&mappings, cur, list) {
03706       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03707       ast_rdlock_contexts();
03708       con = NULL;
03709       while ((con = ast_walk_contexts(con))) {
03710          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03711             continue;
03712          /* Found the match, now queue them all up */
03713          ast_rdlock_context(con);
03714          e = NULL;
03715          while ((e = ast_walk_context_extensions(con, e)))
03716             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03717          ast_unlock_context(con);
03718       }
03719       ast_unlock_contexts();
03720    }
03721 }

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

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

03724 {
03725    struct dundi_request dr;
03726    struct dundi_hint_metadata hmd;
03727    struct dundi_result dr2[MAX_RESULTS];
03728    struct timeval start;
03729    struct dundi_mapping *maps = NULL, *cur;
03730    int nummaps = 0;
03731    int foundanswers;
03732    int foundcache, skipped, ttlms, ms;
03733    if (!context)
03734       context = "e164";
03735    ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
03736 
03737    AST_LIST_LOCK(&peers);
03738    AST_LIST_TRAVERSE(&mappings, cur, list) {
03739       if (!strcasecmp(cur->dcontext, context))
03740          nummaps++;
03741    }
03742    if (nummaps) {
03743       maps = alloca(nummaps * sizeof(*maps));
03744       nummaps = 0;
03745       if (maps) {
03746          AST_LIST_TRAVERSE(&mappings, cur, list) {
03747             if (!strcasecmp(cur->dcontext, context))
03748                maps[nummaps++] = *cur;
03749          }
03750       }
03751    }
03752    AST_LIST_UNLOCK(&peers);
03753    if (!nummaps || !maps)
03754       return -1;
03755    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03756    memset(&dr2, 0, sizeof(dr2));
03757    memset(&dr, 0, sizeof(dr));
03758    memset(&hmd, 0, sizeof(hmd));
03759    dr.dr = dr2;
03760    ast_copy_string(dr.number, number, sizeof(dr.number));
03761    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03762    dr.maxcount = MAX_RESULTS;
03763    dr.expiration = dundi_cache_time;
03764    dr.hmd = &hmd;
03765    dr.pfds[0] = dr.pfds[1] = -1;
03766    if (pipe(dr.pfds) < 0) {
03767       ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno));
03768       return -1;
03769    }
03770    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03771    optimize_transactions(&dr, 0);
03772    foundanswers = 0;
03773    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03774    if (foundanswers) {
03775       if (dr.expiration > 0) 
03776          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03777       else
03778          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03779    }
03780    start = ast_tvnow();
03781    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03782       if (dr.pfds[0] > -1) {
03783          ms = 100;
03784          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03785       } else
03786          usleep(1);
03787    }
03788    cancel_request(&dr);
03789    if (dr.pfds[0] > -1) {
03790       close(dr.pfds[0]);
03791       close(dr.pfds[1]);
03792    }
03793    return 0;
03794 }

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

Definition at line 622 of file pbx_dundi.c.

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

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

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

Definition at line 841 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_clear_flag_nonstd, ast_copy_string(), ast_eid_to_str(), dundi_ies::called_context, dundi_ies::called_number, dundi_answer::data, dundi_result::dest, dundi_request::dr, dr, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_answer::eid, dundi_ies::expiration, dundi_answer::flags, dundi_request::hmd, MAX_RESULTS, dundi_request::maxcount, dundi_transaction::parent, dundi_answer::protocol, dundi_request::respcount, s, tech2str(), dundi_result::techint, dundi_result::weight, and dundi_answer::weight.

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

03233 {
03234    struct dundi_ie_data ied;
03235    int x;
03236    if (!trans->parent) {
03237       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03238       return -1;
03239    }
03240    memset(&ied, 0, sizeof(ied));
03241    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03242    if (!dundi_eid_zero(&trans->us_eid))
03243       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03244    for (x=0;x<trans->eidcount;x++)
03245       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03246    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03247    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03248    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03249    if (trans->autokilltimeout)
03250       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03251    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03252 }

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

Retrieve information on a specific EID.

Definition at line 3849 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03850 {
03851    dundi_eid *avoid[1] = { NULL, };
03852    struct dundi_hint_metadata hmd;
03853    memset(&hmd, 0, sizeof(hmd));
03854    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03855 }

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

03803 {
03804    int res;
03805    struct dundi_request dr;
03806    dundi_eid *rooteid=NULL;
03807    int x;
03808    int ttlms;
03809    int skipped=0;
03810    int foundcache=0;
03811    struct timeval start;
03812    
03813    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03814 
03815    for (x=0;avoid[x];x++)
03816       rooteid = avoid[x];
03817    /* Now perform real check */
03818    memset(&dr, 0, sizeof(dr));
03819    dr.hmd = hmd;
03820    dr.dei = dei;
03821    dr.pfds[0] = dr.pfds[1] = -1;
03822    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03823    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03824    if (rooteid)
03825       dr.root_eid = *rooteid;
03826    /* Create transactions */
03827    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03828 
03829    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03830       do this earlier because we didn't know if we were going to have transactions
03831       or not. */
03832    if (!ttl) {
03833       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03834       return 0;
03835    }
03836       
03837    /* Optimize transactions */
03838    optimize_transactions(&dr, 9999);
03839    /* Actually perform transactions */
03840    query_transactions(&dr);
03841    /* Wait for transaction to come back */
03842    start = ast_tvnow();
03843    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03844       usleep(1);
03845    res = dr.respcount;
03846    return res;
03847 }

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

Definition at line 3955 of file pbx_dundi.c.

References ARRAY_LEN, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, 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().

03956 {
03957    struct ast_module_user *u;
03958    AST_DECLARE_APP_ARGS(args,
03959       AST_APP_ARG(number);
03960       AST_APP_ARG(context);
03961       AST_APP_ARG(options);
03962    );
03963    struct ast_flags opts = { 0, };
03964    char *parse;
03965    struct dundi_result_datastore *drds;
03966    struct ast_datastore *datastore;
03967 
03968    u = ast_module_user_add(chan);
03969 
03970    if (ast_strlen_zero(data)) {
03971       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
03972       ast_module_user_remove(u);
03973       return -1;
03974    }
03975 
03976    if (!chan) {
03977       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
03978       ast_module_user_remove(u);
03979       return -1;
03980    }
03981 
03982    parse = ast_strdupa(data);
03983 
03984    AST_STANDARD_APP_ARGS(args, parse);
03985    
03986    if (!ast_strlen_zero(args.options))
03987       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03988 
03989    if (ast_strlen_zero(args.context))
03990       args.context = "e164";
03991 
03992    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
03993       ast_module_user_remove(u);
03994       return -1;
03995    }
03996 
03997    drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
03998    snprintf(buf, len, "%u", drds->id);
03999 
04000    if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) {
04001       drds_destroy(drds);
04002       ast_module_user_remove(u);
04003       return -1;
04004    }
04005 
04006    datastore->data = drds;
04007 
04008    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, 
04009       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04010 
04011    if (drds->num_results > 0)
04012       sort_results(drds->results, drds->num_results);
04013 
04014    ast_channel_lock(chan);
04015    ast_channel_datastore_add(chan, datastore);
04016    ast_channel_unlock(chan);
04017 
04018    ast_module_user_remove(u);
04019 
04020    return 0;
04021 }

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

Definition at line 655 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, 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().

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

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

Definition at line 367 of file pbx_dundi.c.

References dundi_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 4035 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.

04036 {
04037    struct ast_module_user *u;
04038    AST_DECLARE_APP_ARGS(args,
04039       AST_APP_ARG(id);
04040       AST_APP_ARG(resultnum);
04041    );
04042    char *parse;
04043    unsigned int num;
04044    struct dundi_result_datastore *drds;
04045    struct ast_datastore *datastore;
04046    int res = -1;
04047 
04048    u = ast_module_user_add(chan);
04049 
04050    if (ast_strlen_zero(data)) {
04051       ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n");
04052       goto finish;
04053    }
04054 
04055    if (!chan) {
04056       ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n");
04057       goto finish;
04058    }
04059 
04060    parse = ast_strdupa(data);
04061 
04062    AST_STANDARD_APP_ARGS(args, parse);
04063 
04064    if (ast_strlen_zero(args.id)) {
04065       ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n");
04066       goto finish;
04067    }
04068 
04069    if (ast_strlen_zero(args.resultnum)) {
04070       ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n");
04071       goto finish;
04072    }
04073    
04074    ast_channel_lock(chan);
04075    datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id);
04076    ast_channel_unlock(chan);
04077 
04078    if (!datastore) {
04079       ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id);
04080       goto finish;
04081    }
04082 
04083    drds = datastore->data;
04084 
04085    if (!strcasecmp(args.resultnum, "getnum")) {
04086       snprintf(buf, len, "%u", drds->num_results);
04087       res = 0;
04088       goto finish;
04089    }
04090 
04091    if (sscanf(args.resultnum, "%u", &num) != 1) {
04092       ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n", 
04093          args.resultnum);
04094       goto finish;
04095    }
04096 
04097    if (num && num <= drds->num_results) {
04098       snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest);
04099       res = 0;
04100    } else
04101       ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id);
04102 
04103 finish:
04104    ast_module_user_remove(u);
04105 
04106    return res;
04107 }

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

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

03016 {
03017    struct dundi_packet *pack = (struct dundi_packet *)data;
03018    int res;
03019    AST_LIST_LOCK(&peers);
03020    if (pack->retrans < 1) {
03021       pack->retransid = -1;
03022       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
03023          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
03024             ast_inet_ntoa(pack->parent->addr.sin_addr), 
03025             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
03026       destroy_trans(pack->parent, 1);
03027       res = 0;
03028    } else {
03029       /* Decrement retransmission, try again */
03030       pack->retrans--;
03031       dundi_xmit(pack);
03032       res = 1;
03033    }
03034    AST_LIST_UNLOCK(&peers);
03035    return res;
03036 }

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

Definition at line 3038 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, ast_eid_to_str(), ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_sched_add(), ast_set_flag, ast_test_flag, dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_ACK, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_FINAL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_DEFAULT_RETRANS, dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, dundi_packet::h, dundi_hdr::ies, dundi_transaction::iseqno, dundi_hdr::iseqno, len(), 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().

03039 {
03040    struct dundi_packet *pack;
03041    int res;
03042    int len;
03043    char eid_str[20];
03044    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
03045    /* Reserve enough space for encryption */
03046    if (ast_test_flag(trans, FLAG_ENCRYPT))
03047       len += 384;
03048    pack = ast_calloc(1, len);
03049    if (pack) {
03050       pack->h = (struct dundi_hdr *)(pack->data);
03051       if (cmdresp != DUNDI_COMMAND_ACK) {
03052          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
03053          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
03054          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
03055       }
03056       pack->parent = trans;
03057       pack->h->strans = htons(trans->strans);
03058       pack->h->dtrans = htons(trans->dtrans);
03059       pack->h->iseqno = trans->iseqno;
03060       pack->h->oseqno = trans->oseqno;
03061       pack->h->cmdresp = cmdresp;
03062       pack->datalen = sizeof(struct dundi_hdr);
03063       if (ied) {
03064          memcpy(pack->h->ies, ied->buf, ied->pos);
03065          pack->datalen += ied->pos;
03066       } 
03067       if (final) {
03068          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
03069          ast_set_flag(trans, FLAG_FINAL);
03070       }
03071       pack->h->cmdflags = flags;
03072       if (cmdresp != DUNDI_COMMAND_ACK) {
03073          trans->oseqno++;
03074          trans->oseqno = trans->oseqno % 256;
03075       }
03076       trans->aseqno = trans->iseqno;
03077       /* If we have their public key, encrypt */
03078       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
03079          switch(cmdresp) {
03080          case DUNDI_COMMAND_REGREQ:
03081          case DUNDI_COMMAND_REGRESPONSE:
03082          case DUNDI_COMMAND_DPDISCOVER:
03083          case DUNDI_COMMAND_DPRESPONSE:
03084          case DUNDI_COMMAND_EIDQUERY:
03085          case DUNDI_COMMAND_EIDRESPONSE:
03086          case DUNDI_COMMAND_PRECACHERQ:
03087          case DUNDI_COMMAND_PRECACHERP:
03088             if (dundidebug)
03089                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
03090             res = dundi_encrypt(trans, pack);
03091             break;
03092          default:
03093             res = 0;
03094          }
03095       } else 
03096          res = 0;
03097       if (!res) 
03098          res = dundi_xmit(pack);
03099       if (res)
03100          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03101             
03102       if (cmdresp == DUNDI_COMMAND_ACK)
03103          ast_free(pack);
03104       return res;
03105    }
03106    return -1;
03107 }

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

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

02220 {
02221    switch (cmd) {
02222    case CLI_INIT:
02223       e->command = "dundi set debug {on|off}";
02224       e->usage = 
02225          "Usage: dundi set debug {on|off}\n"
02226          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02227       return NULL;
02228    case CLI_GENERATE:
02229       return NULL;
02230    }
02231 
02232    if (a->argc != e->args)
02233       return CLI_SHOWUSAGE;
02234 
02235    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02236       dundidebug = 1;
02237       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02238    } else {
02239       dundidebug = 0;
02240       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02241    }
02242    return CLI_SUCCESS;
02243 }

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

Definition at line 2734 of file pbx_dundi.c.

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

02735 {
02736    char eid_str[20];
02737    switch (cmd) {
02738    case CLI_INIT:
02739       e->command = "dundi show entityid";
02740       e->usage =
02741          "Usage: dundi show entityid\n"
02742          "       Displays the global entityid for this host.\n";
02743       return NULL;
02744    case CLI_GENERATE:
02745       return NULL;
02746    }
02747    if (a->argc != 3)
02748       return CLI_SHOWUSAGE;
02749    AST_LIST_LOCK(&peers);
02750    ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02751    AST_LIST_UNLOCK(&peers);
02752    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02753    return CLI_SUCCESS;
02754 }

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

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

02789 {
02790 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02791 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02792    struct dundi_mapping *map;
02793    char fs[256];
02794    char weight[8];
02795    switch (cmd) {
02796    case CLI_INIT:
02797       e->command = "dundi show mappings";
02798       e->usage = 
02799          "Usage: dundi show mappings\n"
02800          "       Lists all known DUNDi mappings.\n";
02801       return NULL;
02802    case CLI_GENERATE:
02803       return NULL;
02804    }
02805    if (a->argc != 3)
02806       return CLI_SHOWUSAGE;
02807    AST_LIST_LOCK(&peers);
02808    ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02809    AST_LIST_TRAVERSE(&mappings, map, list) {
02810       snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map));
02811       ast_cli(a->fd, FORMAT, map->dcontext, weight,
02812          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02813          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02814    }
02815    AST_LIST_UNLOCK(&peers);
02816    return CLI_SUCCESS;
02817 #undef FORMAT
02818 #undef FORMAT2
02819 }

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

Definition at line 2537 of file pbx_dundi.c.

References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_strlen_zero(), dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_peer_helper(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, dundi_peer::include, dundi_peer::inkey, ast_cli_args::line, 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.

02538 {
02539    struct dundi_peer *peer;
02540    struct permission *p;
02541    char *order;
02542    char eid_str[20];
02543    int x, cnt;
02544    switch (cmd) {
02545    case CLI_INIT:
02546       e->command = "dundi show peer";
02547       e->usage =
02548          "Usage: dundi show peer [peer]\n"
02549          "       Provide a detailed description of a specifid DUNDi peer.\n";
02550       return NULL;
02551    case CLI_GENERATE:
02552       return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
02553    }
02554    if (a->argc != 4)
02555       return CLI_SHOWUSAGE;
02556    AST_LIST_LOCK(&peers);
02557    AST_LIST_TRAVERSE(&peers, peer, list) {
02558       if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
02559          break;
02560    }
02561    if (peer) {
02562       switch(peer->order) {
02563       case 0:
02564          order = "Primary";
02565          break;
02566       case 1:
02567          order = "Secondary";
02568          break;
02569       case 2:
02570          order = "Tertiary";
02571          break;
02572       case 3:
02573          order = "Quartiary";
02574          break;
02575       default:
02576          order = "Unknown";
02577       }
02578       ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02579       ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));
02580       ast_cli(a->fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02581       ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02582       ast_cli(a->fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02583       ast_cli(a->fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02584       ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02585       if (!AST_LIST_EMPTY(&peer->include))
02586          ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02587       AST_LIST_TRAVERSE(&peer->include, p, list)
02588          ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02589       if (!AST_LIST_EMPTY(&peer->permit))
02590          ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02591       AST_LIST_TRAVERSE(&peer->permit, p, list)
02592          ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02593       cnt = 0;
02594       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02595          if (peer->lookups[x]) {
02596             if (!cnt)
02597                ast_cli(a->fd, "Last few query times:\n");
02598             ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02599             cnt++;
02600          }
02601       }
02602       if (cnt)
02603          ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms);
02604    } else
02605       ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]);
02606    AST_LIST_UNLOCK(&peers);
02607    return CLI_SUCCESS;
02608 }

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

Definition at line 2610 of file pbx_dundi.c.

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

02611 {
02612 #define FORMAT2 "%-20.20s %-15.15s     %-10.10s %-8.8s %-15.15s\n"
02613 #define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
02614    struct dundi_peer *peer;
02615    int registeredonly=0;
02616    char avgms[20];
02617    char eid_str[20];
02618    int online_peers = 0;
02619    int offline_peers = 0;
02620    int unmonitored_peers = 0;
02621    int total_peers = 0;
02622    switch (cmd) {
02623    case CLI_INIT:
02624       e->command = "dundi show peers [registered|include|exclude|begin]";
02625       e->usage = 
02626          "Usage: dundi show peers [registered|include|exclude|begin]\n"
02627          "       Lists all known DUNDi peers.\n"
02628          "       If 'registered' is present, only registered peers are shown.\n";
02629       return NULL;
02630    case CLI_GENERATE:
02631       return NULL;
02632    }
02633 
02634    if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5))
02635       return CLI_SHOWUSAGE;
02636    if ((a->argc == 4)) {
02637       if (!strcasecmp(a->argv[3], "registered")) {
02638          registeredonly = 1;
02639       } else
02640          return CLI_SHOWUSAGE;
02641    }
02642    AST_LIST_LOCK(&peers);
02643    ast_cli(a->fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status");
02644    AST_LIST_TRAVERSE(&peers, peer, list) {
02645       char status[20];
02646       int print_line = -1;
02647       char srch[2000];
02648       total_peers++;
02649       if (registeredonly && !peer->addr.sin_addr.s_addr)
02650          continue;
02651       if (peer->maxms) {
02652          if (peer->lastms < 0) {
02653             strcpy(status, "UNREACHABLE");
02654             offline_peers++;
02655          }
02656          else if (peer->lastms > peer->maxms) {
02657             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02658             offline_peers++;
02659          }
02660          else if (peer->lastms) {
02661             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02662             online_peers++;
02663          }
02664          else {
02665             strcpy(status, "UNKNOWN");
02666             offline_peers++;
02667          }
02668       } else {
02669          strcpy(status, "Unmonitored");
02670          unmonitored_peers++;
02671       }
02672       if (peer->avgms) 
02673          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02674       else
02675          strcpy(avgms, "Unavail");
02676       snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02677                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02678                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02679 
02680                 if (a->argc == 5) {
02681                   if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {
02682                         print_line = -1;
02683                    } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) {
02684                         print_line = 1;
02685                    } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) {
02686                         print_line = -1;
02687                    } else {
02688                         print_line = 0;
02689                   }
02690                 }
02691       
02692         if (print_line) {
02693          ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02694                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02695                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02696       }
02697    }
02698    ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02699    AST_LIST_UNLOCK(&peers);
02700    return CLI_SUCCESS;
02701 #undef FORMAT
02702 #undef FORMAT2
02703 }

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

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

02822 {
02823 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02824 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02825    struct dundi_precache_queue *qe;
02826    int h,m,s;
02827    time_t now;
02828    switch (cmd) {
02829    case CLI_INIT:
02830       e->command = "dundi show precache";
02831       e->usage = 
02832          "Usage: dundi show precache\n"
02833          "       Lists all known DUNDi scheduled precache updates.\n";
02834       return NULL;
02835    case CLI_GENERATE:
02836       return NULL;
02837    }
02838    if (a->argc != 3)
02839       return CLI_SHOWUSAGE;
02840    time(&now);
02841    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
02842    AST_LIST_LOCK(&pcq);
02843    AST_LIST_TRAVERSE(&pcq, qe, list) {
02844       s = qe->expiration - now;
02845       h = s / 3600;
02846       s = s % 3600;
02847       m = s / 60;
02848       s = s % 60;
02849       ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
02850    }
02851    AST_LIST_UNLOCK(&pcq);
02852    
02853    return CLI_SUCCESS;
02854 #undef FORMAT
02855 #undef FORMAT2
02856 }

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

Definition at line 2756 of file pbx_dundi.c.

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

02757 {
02758 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02759 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02760    struct dundi_request *req;
02761    char eidstr[20];
02762    switch (cmd) {
02763    case CLI_INIT:
02764       e->command = "dundi show requests";
02765       e->usage = 
02766          "Usage: dundi show requests\n"
02767          "       Lists all known pending DUNDi requests.\n";
02768       return NULL;
02769    case CLI_GENERATE:
02770       return NULL;
02771    }
02772    if (a->argc != 3)
02773       return CLI_SHOWUSAGE;
02774    AST_LIST_LOCK(&peers);
02775    ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02776    AST_LIST_TRAVERSE(&requests, req, list) {
02777       ast_cli(a->fd, FORMAT, req->number, req->dcontext,
02778          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02779    }
02780    AST_LIST_UNLOCK(&peers);
02781    return CLI_SUCCESS;
02782 #undef FORMAT
02783 #undef FORMAT2
02784 }

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

Definition at line 2705 of file pbx_dundi.c.

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

02706 {
02707 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02708 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02709    struct dundi_transaction *trans;
02710    switch (cmd) {
02711    case CLI_INIT:
02712       e->command = "dundi show trans";
02713       e->usage = 
02714          "Usage: dundi show trans\n"
02715          "       Lists all known DUNDi transactions.\n";
02716       return NULL;
02717    case CLI_GENERATE:
02718       return NULL;
02719    }
02720    if (a->argc != 3)
02721       return CLI_SHOWUSAGE;
02722    AST_LIST_LOCK(&peers);
02723    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02724    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02725       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02726          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02727    }
02728    AST_LIST_UNLOCK(&peers);
02729    return CLI_SUCCESS;
02730 #undef FORMAT
02731 #undef FORMAT2
02732 }

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

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

02272 {
02273    switch (cmd) {
02274    case CLI_INIT:
02275       e->command = "dundi store history {on|off}";
02276       e->usage = 
02277          "Usage: dundi store history {on|off}\n"
02278          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02279          "purposes\n";
02280       return NULL;
02281    case CLI_GENERATE:
02282       return NULL;
02283    }
02284 
02285    if (a->argc != e->args)
02286       return CLI_SHOWUSAGE;
02287    
02288    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02289       global_storehistory = 1;
02290       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02291    } else {
02292       global_storehistory = 0;
02293       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02294    }
02295    return CLI_SUCCESS;
02296 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02908 {
02909    int res;
02910    if (dundidebug)
02911       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02912    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02913    if (res < 0) {
02914       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02915          ast_inet_ntoa(pack->parent->addr.sin_addr),
02916          ntohs(pack->parent->addr.sin_port), strerror(errno));
02917    }
02918    if (res > 0)
02919       res = 0;
02920    return res;
02921 }

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

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

03858 {
03859    char *context;
03860    char *opts;
03861    int results;
03862    int x;
03863    int bypass = 0;
03864    struct ast_module_user *u;
03865    struct dundi_result dr[MAX_RESULTS];
03866 
03867    buf[0] = '\0';
03868 
03869    if (ast_strlen_zero(num)) {
03870       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03871       return -1;
03872    }
03873 
03874    u = ast_module_user_add(chan);
03875 
03876    context = strchr(num, '|');
03877    if (context) {
03878       *context++ = '\0';
03879       opts = strchr(context, '|');
03880       if (opts) {
03881          *opts++ = '\0';
03882          if (strchr(opts, 'b'))
03883             bypass = 1;
03884       }
03885    }
03886 
03887    if (ast_strlen_zero(context))
03888       context = "e164";
03889    
03890    results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
03891    if (results > 0) {
03892       sort_results(dr, results);
03893       for (x = 0; x < results; x++) {
03894          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03895             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03896             break;
03897          }
03898       }
03899    }
03900 
03901    ast_module_user_remove(u);
03902 
03903    return 0;
03904 }

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

Definition at line 1270 of file pbx_dundi.c.

References ast_aes_encrypt.

Referenced by dundi_encrypt().

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

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

Definition at line 427 of file pbx_dundi.c.

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

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

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

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

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

Referenced by dundi_lookup_local(), and dundi_show_mappings().

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

static int get_trans_id ( void   )  [static]

Definition at line 392 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1477 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_eid_to_str(), 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_ies::called_context, dundi_ies::called_number, dundi_ies::cause, dundi_hdr::cmdresp, dundi_hint::data, dundi_answer::data, 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_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_answer::eid, dundi_peer::eid, dundi_ies::eidcount, dundi_ies::eids, dundi_request::expiration, dundi_ies::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, dundi_answer::flags, has_permission(), dundi_ies::hint, dundi_request::hmd, dundi_hdr::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, dundi_answer::protocol, 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, dundi_result::weight, and dundi_answer::weight.

Referenced by handle_frame().

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

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

Definition at line 1937 of file pbx_dundi.c.

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

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

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

Definition at line 281 of file pbx_dundi.c.

References permission::allow, AST_LIST_TRAVERSE, 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 4822 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().

04823 {
04824    struct sockaddr_in sin;
04825 
04826    dundi_set_output(dundi_debug_output);
04827    dundi_set_error(dundi_error_output);
04828    
04829    sin.sin_family = AF_INET;
04830    sin.sin_port = ntohs(DUNDI_PORT);
04831    sin.sin_addr.s_addr = INADDR_ANY;
04832 
04833    /* Make a UDP socket */
04834    io = io_context_create();
04835    sched = sched_context_create();
04836    
04837    if (!io || !sched)
04838       return AST_MODULE_LOAD_FAILURE;
04839 
04840    if (set_config("dundi.conf", &sin, 0))
04841       return AST_MODULE_LOAD_DECLINE;
04842 
04843    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04844    
04845    if (netsocket < 0) {
04846       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04847       return AST_MODULE_LOAD_FAILURE;
04848    }
04849    if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {
04850       ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", 
04851          ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
04852       return AST_MODULE_LOAD_FAILURE;
04853    }
04854    
04855    ast_netsock_set_qos(netsocket, tos, 0, "DUNDi");
04856    
04857    if (start_network_thread()) {
04858       ast_log(LOG_ERROR, "Unable to start network thread\n");
04859       close(netsocket);
04860       return AST_MODULE_LOAD_FAILURE;
04861    }
04862    
04863    ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(*cli_dundi));
04864    if (ast_register_switch(&dundi_switch))
04865       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04866    ast_custom_function_register(&dundi_function);
04867    ast_custom_function_register(&dundi_query_function);
04868    ast_custom_function_register(&dundi_result_function);
04869    
04870    ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04871 
04872    return AST_MODULE_LOAD_SUCCESS;
04873 }

static void load_password ( void   )  [static]

Definition at line 2034 of file pbx_dundi.c.

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

Referenced by set_config().

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

static void mark_mappings ( void   )  [static]

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

04133 {
04134    struct dundi_mapping *map;
04135    
04136    AST_LIST_LOCK(&peers);
04137    AST_LIST_TRAVERSE(&mappings, map, list) {
04138       map->dead = 1;
04139    }
04140    AST_LIST_UNLOCK(&peers);
04141 }

static void mark_peers ( void   )  [static]

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

04123 {
04124    struct dundi_peer *peer;
04125    AST_LIST_LOCK(&peers);
04126    AST_LIST_TRAVERSE(&peers, peer, list) {
04127       peer->dead = 1;
04128    }
04129    AST_LIST_UNLOCK(&peers);
04130 }

static char* model2str ( int  model  )  [static]

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

02344 {
02345    switch(model) {
02346    case DUNDI_MODEL_INBOUND:
02347       return "Inbound";
02348    case DUNDI_MODEL_OUTBOUND:
02349       return "Outbound";
02350    case DUNDI_MODEL_SYMMETRIC:
02351       return "Symmetric";
02352    default:
02353       return "Unknown";
02354    }
02355 }

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

Definition at line 2090 of file pbx_dundi.c.

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

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

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

Definition at line 3313 of file pbx_dundi.c.

References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, dr, 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().

03314 {
03315    /* Minimize the message propagation through DUNDi by
03316       alerting the network to hops which should be not be considered */
03317    struct dundi_transaction *trans;
03318    struct dundi_peer *peer;
03319    dundi_eid tmp;
03320    int x;
03321    int needpush;
03322 
03323    AST_LIST_LOCK(&peers);
03324    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03325       /* Pop off the true root */
03326       if (trans->eidcount) {
03327          tmp = trans->eids[--trans->eidcount];
03328          needpush = 1;
03329       } else {
03330          tmp = trans->us_eid;
03331          needpush = 0;
03332       }
03333 
03334       AST_LIST_TRAVERSE(&peers, peer, list) {
03335          if (has_permission(&peer->include, dr->dcontext) && 
03336              ast_eid_cmp(&peer->eid, &trans->them_eid) &&
03337             (peer->order <= order)) {
03338             /* For each other transaction, make sure we don't
03339                ask this EID about the others if they're not
03340                already in the list */
03341             if (!ast_eid_cmp(&tmp, &peer->eid)) 
03342                x = -1;
03343             else {
03344                for (x=0;x<trans->eidcount;x++) {
03345                   if (!ast_eid_cmp(&trans->eids[x], &peer->eid))
03346                      break;
03347                }
03348             }
03349             if (x == trans->eidcount) {
03350                /* Nope not in the list, if needed, add us at the end since we're the source */
03351                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03352                   trans->eids[trans->eidcount++] = peer->eid;
03353                   /* Need to insert the real root (or us) at the bottom now as
03354                      a requirement now.  */
03355                   needpush = 1;
03356                }
03357             }
03358          }
03359       }
03360       /* If necessary, push the true root back on the end */
03361       if (needpush)
03362          trans->eids[trans->eidcount++] = tmp;
03363    }
03364    AST_LIST_UNLOCK(&peers);
03365 
03366    return 0;
03367 }

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

Definition at line 4345 of file pbx_dundi.c.

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

Referenced by build_peer().

04346 {
04347    char data[256];
04348    char *c;
04349    int port, expire;
04350    char eid_str[20];
04351    ast_eid_to_str(eid_str, sizeof(eid_str), eid);
04352    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04353       c = strchr(data, ':');
04354       if (c) {
04355          *c = '\0';
04356          c++;
04357          if (sscanf(c, "%d:%d", &port, &expire) == 2) {
04358             /* Got it! */
04359             inet_aton(data, &peer->addr.sin_addr);
04360             peer->addr.sin_family = AF_INET;
04361             peer->addr.sin_port = htons(port);
04362             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04363          }
04364       }
04365    }
04366 }

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

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

03167 {
03168    struct dundi_ie_data ied;
03169    int x, res;
03170    int max = 999999;
03171    int expiration = dundi_cache_time;
03172    int ouranswers=0;
03173    dundi_eid *avoid[1] = { NULL, };
03174    int direct[1] = { 0, };
03175    struct dundi_result dr[MAX_RESULTS];
03176    struct dundi_hint_metadata hmd;
03177    if (!trans->parent) {
03178       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03179       return -1;
03180    }
03181    memset(&hmd, 0, sizeof(hmd));
03182    memset(&dr, 0, sizeof(dr));
03183    /* Look up the answers we're going to include */
03184    for (x=0;x<mapcount;x++)
03185       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03186    if (ouranswers < 0)
03187       ouranswers = 0;
03188    for (x=0;x<ouranswers;x++) {
03189       if (dr[x].weight < max)
03190          max = dr[x].weight;
03191    }
03192    if (max) {
03193       /* If we do not have a canonical result, keep looking */
03194       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);
03195       if (res > 0) {
03196          /* Append answer in result */
03197          ouranswers += res;
03198       }
03199    }
03200    
03201    if (ouranswers > 0) {
03202       *foundanswers += ouranswers;
03203       memset(&ied, 0, sizeof(ied));
03204       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03205       if (!dundi_eid_zero(&trans->us_eid))
03206          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03207       for (x=0;x<trans->eidcount;x++)
03208          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03209       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03210       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03211       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03212       for (x=0;x<ouranswers;x++) {
03213          /* Add answers */
03214          if (dr[x].expiration && (expiration > dr[x].expiration))
03215             expiration = dr[x].expiration;
03216          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03217       }
03218       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03219       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03220       if (trans->autokilltimeout)
03221          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03222       if (expiration < *minexp)
03223          *minexp = expiration;
03224       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03225    } else {
03226       /* Oops, nothing to send... */
03227       destroy_trans(trans, 0);
03228       return 0;
03229    }
03230 }

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

Definition at line 3265 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, precache_trans(), and dundi_transaction::thread.

Referenced by dundi_precache_internal().

03266 {
03267    struct dundi_transaction *trans;
03268 
03269    /* Mark all as "in thread" so they don't disappear */
03270    AST_LIST_LOCK(&peers);
03271    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03272       if (trans->thread)
03273          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03274       trans->thread = 1;
03275    }
03276    AST_LIST_UNLOCK(&peers);
03277 
03278    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03279       if (!ast_test_flag(trans, FLAG_DEAD))
03280          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03281    }
03282 
03283    /* Cleanup any that got destroyed in the mean time */
03284    AST_LIST_LOCK(&peers);
03285    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03286       trans->thread = 0;
03287       if (ast_test_flag(trans, FLAG_DEAD)) {
03288          ast_debug(1, "Our transaction went away!\n");
03289          /* This is going to remove the transaction from the dundi_request's list, as well
03290           * as the global transactions list */
03291          destroy_trans(trans, 0);
03292       }
03293    }
03294    AST_LIST_TRAVERSE_SAFE_END
03295    AST_LIST_UNLOCK(&peers);
03296 
03297    return 0;
03298 }

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

Definition at line 2116 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

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

Definition at line 2150 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

static void prune_mappings ( void   )  [static]

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

04185 {
04186    struct dundi_mapping *map;
04187 
04188    AST_LIST_LOCK(&peers);
04189    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
04190       if (map->dead) {
04191          AST_LIST_REMOVE_CURRENT(list);
04192          destroy_map(map);
04193       }
04194    }
04195    AST_LIST_TRAVERSE_SAFE_END;
04196    AST_LIST_UNLOCK(&peers);
04197 }

static void prune_peers ( void   )  [static]

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

04170 {
04171    struct dundi_peer *peer;
04172 
04173    AST_LIST_LOCK(&peers);
04174    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
04175       if (peer->dead) {
04176          AST_LIST_REMOVE_CURRENT(list);
04177          destroy_peer(peer);
04178       }
04179    }
04180    AST_LIST_TRAVERSE_SAFE_END;
04181    AST_LIST_UNLOCK(&peers);
04182 }

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

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

04323 {
04324    int when;
04325    AST_SCHED_DEL(sched, peer->qualifyid);
04326    if (peer->qualtrans)
04327       destroy_trans(peer->qualtrans, 0);
04328    peer->qualtrans = NULL;
04329    if (peer->maxms > 0) {
04330       when = 60000;
04331       if (peer->lastms < 0)
04332          when = 10000;
04333       if (schedonly)
04334          when = 5000;
04335       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04336       if (!schedonly)
04337          peer->qualtrans = create_transaction(peer);
04338       if (peer->qualtrans) {
04339          peer->qualtx = ast_tvnow();
04340          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04341          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04342       }
04343    }
04344 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3300 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

03301 {
03302    struct dundi_transaction *trans;
03303 
03304    AST_LIST_LOCK(&peers);
03305    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03306       dundi_query(trans);
03307    }
03308    AST_LIST_UNLOCK(&peers);
03309 
03310    return 0;
03311 }

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

Definition at line 3484 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03485 {
03486    struct dundi_request *cur;
03487    int res=0;
03488    char eid_str[20];
03489    AST_LIST_LOCK(&peers);
03490    AST_LIST_TRAVERSE(&requests, cur, list) {
03491       ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03492          dr->dcontext, dr->number);
03493       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03494           !strcasecmp(cur->number, dr->number) &&
03495           (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03496          ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 
03497             cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03498          *pending = cur;
03499          res = 1;
03500          break;
03501       }
03502    }
03503    if (!res) {
03504       ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 
03505             dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03506       /* Go ahead and link us in since nobody else is searching for this */
03507       AST_LIST_INSERT_HEAD(&requests, dr, list);
03508       *pending = NULL;
03509    }
03510    AST_LIST_UNLOCK(&peers);
03511    return res;
03512 }

static int reload ( void   )  [static]

Definition at line 4812 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04813 {
04814    struct sockaddr_in sin;
04815 
04816    if (set_config("dundi.conf", &sin, 1))
04817       return AST_MODULE_LOAD_FAILURE;
04818 
04819    return AST_MODULE_LOAD_SUCCESS;
04820 }

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

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

03664 {
03665    int len;
03666    struct dundi_precache_queue *qe, *prev;
03667 
03668    AST_LIST_LOCK(&pcq);
03669    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03670       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03671          AST_LIST_REMOVE_CURRENT(list);
03672          break;
03673       }
03674    }
03675    AST_LIST_TRAVERSE_SAFE_END;
03676    if (!qe) {
03677       len = sizeof(*qe);
03678       len += strlen(number) + 1;
03679       len += strlen(context) + 1;
03680       if (!(qe = ast_calloc(1, len))) {
03681          AST_LIST_UNLOCK(&pcq);
03682          return;
03683       }
03684       strcpy(qe->number, number);
03685       qe->context = qe->number + strlen(number) + 1;
03686       strcpy(qe->context, context);
03687    }
03688    time(&qe->expiration);
03689    qe->expiration += expiration;
03690    if ((prev = AST_LIST_FIRST(&pcq))) {
03691       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03692          prev = AST_LIST_NEXT(prev, list);
03693       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03694    } else
03695       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03696    AST_LIST_UNLOCK(&pcq);
03697 }

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

Definition at line 2379 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02380 {
02381    const struct dundi_result *resa, *resb;
02382    resa = a;
02383    resb = b;
02384    if (resa->weight < resb->weight)
02385       return -1;
02386    if (resa->weight > resb->weight)
02387       return 1;
02388    return 0;
02389 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

00412 {
00413    int tid;
00414    tid = get_trans_id();
00415    if (tid < 1)
00416       return -1;
00417    trans->strans = tid;
00418    trans->dtrans = 0;
00419    trans->iseqno = 0;
00420    trans->oiseqno = 0;
00421    trans->oseqno = 0;
00422    trans->aseqno = 0;
00423    ast_clear_flag(trans, FLAG_FINAL);  
00424    return 0;
00425 }

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

Definition at line 2021 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02022 {
02023    char tmp[256];
02024    if (oldkey)
02025       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02026    else
02027       snprintf(tmp, sizeof(tmp), "%s", newkey);
02028    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02029    ast_db_put(secretpath, "secret", tmp);
02030    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02031    ast_db_put(secretpath, "secretexpiry", tmp);
02032 }

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

Definition at line 4634 of file pbx_dundi.c.

References any_peer, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_eid_default, ast_gethostbyname(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_str2tos(), ast_str_to_eid(), ast_true(), ast_variable_browse(), build_mapping(), build_peer(), config_flags, DEFAULT_MAXMS, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), 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(), and ast_variable::value.

04635 {
04636    struct ast_config *cfg;
04637    struct ast_variable *v;
04638    char *cat;
04639    int x;
04640    struct ast_flags config_flags = { 0 };
04641    char hn[MAXHOSTNAMELEN] = "";
04642    struct ast_hostent he;
04643    struct hostent *hp;
04644    struct sockaddr_in sin2;
04645    static int last_port = 0;
04646    int globalpcmodel = 0;
04647    dundi_eid testeid;
04648 
04649    if (!(cfg = ast_config_load(config_file, config_flags))) {
04650       ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
04651       return -1;
04652    }
04653 
04654    dundi_ttl = DUNDI_DEFAULT_TTL;
04655    dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
04656    any_peer = NULL;
04657 
04658    ipaddr[0] = '\0';
04659    if (!gethostname(hn, sizeof(hn)-1)) {
04660       hp = ast_gethostbyname(hn, &he);
04661       if (hp) {
04662          memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
04663          ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
04664       } else
04665          ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
04666    } else
04667       ast_log(LOG_WARNING, "Unable to get host name!\n");
04668    AST_LIST_LOCK(&peers);
04669 
04670    memcpy(&global_eid, &ast_eid_default, sizeof(global_eid));
04671 
04672    global_storehistory = 0;
04673    ast_copy_string(secretpath, "dundi", sizeof(secretpath));
04674    v = ast_variable_browse(cfg, "general");
04675    while(v) {
04676       if (!strcasecmp(v->name, "port")){ 
04677          sin->sin_port = ntohs(atoi(v->value));
04678          if(last_port==0){
04679             last_port=sin->sin_port;
04680          } else if(sin->sin_port != last_port)
04681             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
04682       } else if (!strcasecmp(v->name, "bindaddr")) {
04683          struct hostent *hep;
04684          struct ast_hostent hent;
04685          hep = ast_gethostbyname(v->value, &hent);
04686          if (hep) {
04687             memcpy(&sin->sin_addr, hep->h_addr, sizeof(sin->sin_addr));
04688          } else
04689             ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
04690       } else if (!strcasecmp(v->name, "authdebug")) {
04691          authdebug = ast_true(v->value);
04692       } else if (!strcasecmp(v->name, "ttl")) {
04693          if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
04694             dundi_ttl = x;
04695          } else {
04696             ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
04697                v->value, v->lineno, DUNDI_DEFAULT_TTL);
04698          }
04699       } else if (!strcasecmp(v->name, "autokill")) {
04700          if (sscanf(v->value, "%d", &x) == 1) {
04701             if (x >= 0)
04702                global_autokilltimeout = x;
04703             else
04704                ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
04705          } else if (ast_true(v->value)) {
04706             global_autokilltimeout = DEFAULT_MAXMS;
04707          } else {
04708             global_autokilltimeout = 0;
04709          }
04710       } else if (!strcasecmp(v->name, "entityid")) {
04711          if (!ast_str_to_eid(&testeid, v->value))
04712             global_eid = testeid;
04713          else
04714             ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
04715       } else if (!strcasecmp(v->name, "tos")) {
04716          if (ast_str2tos(v->value, &tos)) 
04717             ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04718       } else if (!strcasecmp(v->name, "department")) {
04719          ast_copy_string(dept, v->value, sizeof(dept));
04720       } else if (!strcasecmp(v->name, "organization")) {
04721          ast_copy_string(org, v->value, sizeof(org));
04722       } else if (!strcasecmp(v->name, "locality")) {
04723          ast_copy_string(locality, v->value, sizeof(locality));
04724       } else if (!strcasecmp(v->name, "stateprov")) {
04725          ast_copy_string(stateprov, v->value, sizeof(stateprov));
04726       } else if (!strcasecmp(v->name, "country")) {
04727          ast_copy_string(country, v->value, sizeof(country));
04728       } else if (!strcasecmp(v->name, "email")) {
04729          ast_copy_string(email, v->value, sizeof(email));
04730       } else if (!strcasecmp(v->name, "phone")) {
04731          ast_copy_string(phone, v->value, sizeof(phone));
04732       } else if (!strcasecmp(v->name, "storehistory")) {
04733          global_storehistory = ast_true(v->value);
04734       } else if (!strcasecmp(v->name, "cachetime")) {
04735          if ((sscanf(v->value, "%d", &x) == 1)) {
04736             dundi_cache_time = x;
04737          } else {
04738             ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
04739                v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
04740          }
04741       }
04742       v = v->next;
04743    }
04744    AST_LIST_UNLOCK(&peers);
04745    mark_mappings();
04746    v = ast_variable_browse(cfg, "mappings");
04747    while(v) {
04748       build_mapping(v->name, v->value);
04749       v = v->next;
04750    }
04751    prune_mappings();
04752    mark_peers();
04753    cat = ast_category_browse(cfg, NULL);
04754    while(cat) {
04755       if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
04756          /* Entries */
04757          if (!ast_str_to_eid(&testeid, cat))
04758             build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
04759          else if (!strcasecmp(cat, "*")) {
04760             build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel);
04761             any_peer = find_peer(NULL);
04762          } else
04763             ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
04764       }
04765       cat = ast_category_browse(cfg, cat);
04766    }
04767    prune_peers();
04768    ast_config_destroy(cfg);
04769    load_password();
04770    if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
04771       dundi_precache_full();
04772    return 0;
04773 }

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

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

01979 {
01980    struct sockaddr_in sin;
01981    int res;
01982    struct dundi_hdr *h;
01983    char buf[MAX_PACKET_SIZE];
01984    socklen_t len = sizeof(sin);
01985    
01986    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
01987    if (res < 0) {
01988       if (errno != ECONNREFUSED)
01989          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
01990       return 1;
01991    }
01992    if (res < sizeof(struct dundi_hdr)) {
01993       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
01994       return 1;
01995    }
01996    buf[res] = '\0';
01997    h = (struct dundi_hdr *) buf;
01998    if (dundidebug)
01999       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
02000    AST_LIST_LOCK(&peers);
02001    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
02002    AST_LIST_UNLOCK(&peers);
02003    return 1;
02004 }

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

Definition at line 2391 of file pbx_dundi.c.

References rescomp().

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

02392 {
02393    qsort(results, count, sizeof(results[0]), rescomp);
02394 }

static int start_network_thread ( void   )  [static]

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

04776 {
04777    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid, previous_clearcachethreadid = clearcachethreadid;
04778    ast_module_user_hangup_all();
04779 
04780    /* Stop all currently running threads */
04781    dundi_shutdown = 1;
04782    if (previous_netthreadid != AST_PTHREADT_NULL) {
04783       pthread_kill(previous_netthreadid, SIGURG);
04784       pthread_join(previous_netthreadid, NULL);
04785    }
04786    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04787       pthread_kill(previous_precachethreadid, SIGURG);
04788       pthread_join(previous_precachethreadid, NULL);
04789    }
04790    if (previous_clearcachethreadid != AST_PTHREADT_NULL) {
04791       pthread_cancel(previous_clearcachethreadid);
04792       pthread_join(previous_clearcachethreadid, NULL);
04793    }
04794 
04795    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04796    ast_unregister_switch(&dundi_switch);
04797    ast_custom_function_unregister(&dundi_function);
04798    ast_custom_function_unregister(&dundi_query_function);
04799    ast_custom_function_unregister(&dundi_result_function);
04800    close(netsocket);
04801    io_context_destroy(io);
04802    sched_context_destroy(sched);
04803 
04804    mark_mappings();
04805    prune_mappings();
04806    mark_peers();
04807    prune_peers();
04808 
04809    return 0;
04810 }

static void unregister_request ( struct dundi_request dr  )  [static]

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

03515 {
03516    AST_LIST_LOCK(&peers);
03517    AST_LIST_REMOVE(&requests, dr, list);
03518    AST_LIST_UNLOCK(&peers);
03519 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1231 of file pbx_dundi.c.

References ast_aes_decrypt_key, ast_aes_encrypt_key, ast_eid_to_str(), ast_encrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), ast_sign_bin, build_iv(), 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().

01232 {
01233    unsigned char key[16];
01234    struct ast_key *ekey, *skey;
01235    char eid_str[20];
01236    int res;
01237    if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
01238       build_iv(key);
01239       ast_aes_encrypt_key(key, &peer->us_ecx);
01240       ast_aes_decrypt_key(key, &peer->us_dcx);
01241       ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01242       if (!ekey) {
01243          ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
01244             peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01245          return -1;
01246       }
01247       skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01248       if (!skey) {
01249          ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
01250             peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01251          return -1;
01252       }
01253       if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
01254          ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
01255          return -1;
01256       }
01257       if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
01258          ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
01259          return -1;
01260       }
01261       peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
01262       peer->sentfullkey = 0;
01263       /* Looks good */
01264       time(&peer->keyexpire);
01265       peer->keyexpire += dundi_key_ttl;
01266    }
01267    return 0;
01268 }


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

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

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4879 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 2860 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 2858 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 2859 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 4023 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 3929 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 3950 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 4109 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

unsigned int dundi_result_id

Definition at line 3931 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 4624 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(), 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 Fri Jun 19 12:10:46 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7