Mon Jun 27 16:51:17 2011

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/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 %-6d %-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 %-6.6s %-10.10s %-8.8s %-15.15s\n"
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64
#define MAX_WEIGHT   59999

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Distributed Universal Number Discovery (DUNDi)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .nonoptreq = "res_crypto", }
static struct dundi_peerany_peer
 Wildcard peer.
static struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 0
static pthread_t clearcachethreadid = AST_PTHREADT_NULL
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
static int default_expiration = 60
static char dept [80]
static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME
static struct ast_custom_function dundi_function
static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE
static struct ast_custom_function dundi_query_function
static struct ast_app_option dundi_query_opts [128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, }
static struct ast_datastore_info dundi_result_datastore_info
static struct ast_custom_function dundi_result_function
static unsigned int dundi_result_id
static int dundi_shutdown = 0
static struct ast_switch dundi_switch
static int dundi_ttl = DUNDI_DEFAULT_TTL
static int dundidebug = 0
static char email [80]
static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }
static int global_autokilltimeout = 0
static dundi_eid global_eid
static int global_storehistory = 0
static struct io_contextio
static char ipaddr [80]
static char locality [80]
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char org [80]
static char phone [80]
static pthread_t precachethreadid = AST_PTHREADT_NULL
static time_t rotatetime
static struct 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 167 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 150 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

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

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 172 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 155 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 %-6d %-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 %-6.6s %-10.10s %-8.8s %-15.15s\n"

#define MAX_OPTS   128

Definition at line 4215 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 146 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

Definition at line 144 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 148 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 157 of file pbx_dundi.c.

00157      {
00158    FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
00159    FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
00160    FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
00161    FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
00162    FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
00163    FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
00164    FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
00165 };

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3882 of file pbx_dundi.c.

03882      {
03883    OPT_BYPASS_CACHE = (1 << 0),
03884 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4884 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4884 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3439 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03440 {
03441    struct dundi_transaction *trans;
03442 
03443    AST_LIST_LOCK(&peers);
03444    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03445       /* This will remove the transaction from the list */
03446       destroy_trans(trans, 0);
03447    }
03448    AST_LIST_UNLOCK(&peers);
03449 }

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

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

01993 {
01994    struct dundi_packet *pack;
01995 
01996    /* Ack transmitted packet corresponding to iseqno */
01997    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01998       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01999          destroy_packet(pack, 0);
02000          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
02001             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
02002             destroy_packets(&trans->lasttrans);
02003          }
02004          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
02005          AST_SCHED_DEL(sched, trans->autokillid);
02006          return 1;
02007       }
02008    }
02009 
02010    return 0;
02011 }

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

Definition at line 4202 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

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

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

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

03395 {
03396    struct dundi_transaction *trans;
03397    int x;
03398    char eid_str[20];
03399    char eid_str2[20];
03400 
03401    /* Ignore if not registered */
03402    if (!p->addr.sin_addr.s_addr)
03403       return 0;
03404    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03405       return 0;
03406 
03407    if (ast_strlen_zero(dr->number))
03408       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);
03409    else
03410       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);
03411 
03412    trans = create_transaction(p);
03413    if (!trans)
03414       return -1;
03415    trans->parent = dr;
03416    trans->ttl = ttl;
03417    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03418       trans->eids[x] = *avoid[x];
03419    trans->eidcount = x;
03420    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03421 
03422    return 0;
03423 }

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

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

01272 {
01273    if (!trans->addr.sin_addr.s_addr)
01274       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01275    trans->us_eid = p->us_eid;
01276    trans->them_eid = p->eid;
01277    /* Enable encryption if appropriate */
01278    if (!ast_strlen_zero(p->inkey))
01279       ast_set_flag(trans, FLAG_ENCRYPT);
01280    if (p->maxms) {
01281       trans->autokilltimeout = p->maxms;
01282       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01283       if (p->lastms > 1) {
01284          trans->retranstimer = p->lastms * 2;
01285          /* Keep it from being silly */
01286          if (trans->retranstimer < 150)
01287             trans->retranstimer = 150;
01288       }
01289       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01290          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01291    } else
01292       trans->autokilltimeout = global_autokilltimeout;
01293 }

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

Definition at line 3560 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03561 {
03562    /* Idea is that we're calculating a checksum which is independent of
03563       the order that the EID's are listed in */
03564    uint32_t acrc32 = 0;
03565    int x;
03566    for (x=0;avoid[x];x++) {
03567       /* Order doesn't matter */
03568       if (avoid[x+1]) {
03569          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03570       }
03571    }
03572    return acrc32;
03573 }

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

Definition at line 521 of file pbx_dundi.c.

References ast_random().

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

00522 {
00523    /* XXX Would be nice to be more random XXX */
00524    unsigned int *fluffy;
00525    int x;
00526    fluffy = (unsigned int *)(iv);
00527    for (x=0;x<4;x++)
00528       fluffy[x] = ast_random();
00529 }

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

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

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

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

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

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

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

Definition at line 2082 of file pbx_dundi.c.

References ast_base64encode(), and build_iv().

Referenced by check_password(), and load_password().

02083 {
02084    unsigned char tmp[16];
02085    char *s;
02086    build_iv(tmp);
02087    secret[0] = '\0';
02088    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02089    /* Eliminate potential bad characters */
02090    while((s = strchr(secret, ';'))) *s = '+';
02091    while((s = strchr(secret, '/'))) *s = '+';
02092    while((s = strchr(secret, ':'))) *s = '+';
02093    while((s = strchr(secret, '@'))) *s = '+';
02094 }

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

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

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

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

01220 {
01221    char key[256];
01222    char eid_str[20];
01223    char eidroot_str[20];
01224    time_t now;
01225    int res=0;
01226    int res2=0;
01227    char eid_str_full[20];
01228    char tmp[256]="";
01229    int x;
01230 
01231    time(&now);
01232    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01233    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01234    ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01235    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32);
01236    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01237    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, 0);
01238    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01239    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01240    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01241    x = 0;
01242    if (!req->respcount) {
01243       while(!res2) {
01244          /* Look and see if we have a hint that would preclude us from looking at this
01245             peer for this number. */
01246          if (!(tmp[x] = req->number[x]))
01247             break;
01248          x++;
01249          /* Check for hints */
01250          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32);
01251          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01252          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, 0);
01253          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01254          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01255          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01256          if (res2) {
01257             if (strlen(tmp) > strlen(req->hmd->exten)) {
01258                /* Update meta data if appropriate */
01259                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01260             }
01261          }
01262       }
01263       res |= res2;
01264    }
01265 
01266    return res;
01267 }

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

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

01148 {
01149    char data[1024];
01150    char *ptr, *term, *src;
01151    int tech;
01152    struct ast_flags flags;
01153    int weight;
01154    int length;
01155    int z;
01156    char fs[256];
01157 
01158    /* Build request string */
01159    if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
01160       time_t timeout;
01161       ptr = data;
01162       if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
01163          int expiration = timeout - now;
01164          if (expiration > 0) {
01165             ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
01166             ptr += length + 1;
01167             while((sscanf(ptr, "%30d/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) == 3)) {
01168                ptr += length;
01169                term = strchr(ptr, '|');
01170                if (term) {
01171                   *term = '\0';
01172                   src = strrchr(ptr, '/');
01173                   if (src) {
01174                      *src = '\0';
01175                      src++;
01176                   } else
01177                      src = "";
01178                   ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n",
01179                      tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
01180                   /* Make sure it's not already there */
01181                   for (z=0;z<req->respcount;z++) {
01182                      if ((req->dr[z].techint == tech) &&
01183                          !strcmp(req->dr[z].dest, ptr))
01184                            break;
01185                   }
01186                   if (z == req->respcount) {
01187                      /* Copy into parent responses */
01188                      ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);
01189                      req->dr[req->respcount].weight = weight;
01190                      req->dr[req->respcount].techint = tech;
01191                      req->dr[req->respcount].expiration = expiration;
01192                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
01193                      ast_eid_to_str(req->dr[req->respcount].eid_str,
01194                         sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
01195                      ast_copy_string(req->dr[req->respcount].dest, ptr,
01196                         sizeof(req->dr[req->respcount].dest));
01197                      ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
01198                         sizeof(req->dr[req->respcount].tech));
01199                      req->respcount++;
01200                      ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK);
01201                   } else if (req->dr[z].weight > weight)
01202                      req->dr[z].weight = weight;
01203                   ptr = term + 1;
01204                }
01205             }
01206             /* We found *something* cached */
01207             if (expiration < *lowexpiration)
01208                *lowexpiration = expiration;
01209             return 1;
01210          } else
01211             ast_db_del("dundi/cache", key);
01212       } else
01213          ast_db_del("dundi/cache", key);
01214    }
01215 
01216    return 0;
01217 }

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

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

00877 {
00878    int x;
00879    char key1[256];
00880    char key2[256];
00881    char data[1024];
00882    char eidpeer_str[20];
00883    char eidroot_str[20];
00884    time_t timeout;
00885 
00886    if (expiration < 1)
00887       expiration = dundi_cache_time;
00888 
00889    /* Keep pushes a little longer, cut pulls a little short */
00890    if (push)
00891       expiration += 10;
00892    else
00893       expiration -= 10;
00894    if (expiration < 1)
00895       expiration = 1;
00896    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00897    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00898    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00899    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00900    /* Build request string */
00901    time(&timeout);
00902    timeout += expiration;
00903    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00904    for (x=start;x<req->respcount;x++) {
00905       /* Skip anything with an illegal pipe in it */
00906       if (strchr(req->dr[x].dest, '|'))
00907          continue;
00908       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|",
00909          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest,
00910          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00911    }
00912    ast_db_put("dundi/cache", key1, data);
00913    ast_db_put("dundi/cache", key2, data);
00914    return 0;
00915 }

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

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

00842 {
00843    int unaffected;
00844    char key1[256];
00845    char key2[256];
00846    char eidpeer_str[20];
00847    char eidroot_str[20];
00848    char data[80];
00849    time_t timeout;
00850 
00851    if (expiration < 0)
00852       expiration = dundi_cache_time;
00853 
00854    /* Only cache hint if "don't ask" is there... */
00855    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))
00856       return 0;
00857 
00858    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00859 
00860    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00861    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00862    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00863    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00864 
00865    time(&timeout);
00866    timeout += expiration;
00867    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00868 
00869    ast_db_put("dundi/cache", key1, data);
00870    ast_debug(1, "Caching hint at '%s'\n", key1);
00871    ast_db_put("dundi/cache", key2, data);
00872    ast_debug(1, "Caching hint at '%s'\n", key2);
00873    return 0;
00874 }

static void cancel_request ( struct dundi_request dr  )  [static]

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

03426 {
03427    struct dundi_transaction *trans;
03428 
03429    AST_LIST_LOCK(&peers);
03430    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03431       /* Orphan transaction from request */
03432       trans->parent = NULL;
03433       /* Send final cancel */
03434       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03435    }
03436    AST_LIST_UNLOCK(&peers);
03437 }

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

Definition at line 1470 of file pbx_dundi.c.

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

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

static void check_password ( void   )  [static]

Definition at line 2149 of file pbx_dundi.c.

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

02150 {
02151    char oldsecret[80];
02152    time_t now;
02153 
02154    time(&now);
02155 #if 0
02156    printf("%ld/%ld\n", now, rotatetime);
02157 #endif
02158    if ((now - rotatetime) >= 0) {
02159       /* Time to rotate keys */
02160       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02161       build_secret(cursecret, sizeof(cursecret));
02162       save_secret(cursecret, oldsecret);
02163    }
02164 }

static int check_request ( struct dundi_request dr  )  [static]

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

03547 {
03548    struct dundi_request *cur;
03549 
03550    AST_LIST_LOCK(&peers);
03551    AST_LIST_TRAVERSE(&requests, cur, list) {
03552       if (cur == dr)
03553          break;
03554    }
03555    AST_LIST_UNLOCK(&peers);
03556 
03557    return cur ? 1 : 0;
03558 }

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

Definition at line 2383 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

02384 {
02385    int which=0, len;
02386    char *ret = NULL;
02387    struct dundi_peer *p;
02388    char eid_str[20];
02389 
02390    if (pos != rpos)
02391       return NULL;
02392    AST_LIST_LOCK(&peers);
02393    len = strlen(word);
02394    AST_LIST_TRAVERSE(&peers, p, list) {
02395       const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02396       if (!strncasecmp(word, s, len) && ++which > state) {
02397          ret = ast_strdup(s);
02398          break;
02399       }
02400    }
02401    AST_LIST_UNLOCK(&peers);
02402    return ret;
02403 }

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

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

02902 {
02903    struct dundi_transaction *trans;
02904    int tid;
02905 
02906    /* Don't allow creation of transactions to non-registered peers */
02907    if (p && !p->addr.sin_addr.s_addr)
02908       return NULL;
02909    tid = get_trans_id();
02910    if (tid < 1)
02911       return NULL;
02912    if (!(trans = ast_calloc(1, sizeof(*trans))))
02913       return NULL;
02914 
02915    if (global_storehistory) {
02916       trans->start = ast_tvnow();
02917       ast_set_flag(trans, FLAG_STOREHIST);
02918    }
02919    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02920    trans->autokillid = -1;
02921    if (p) {
02922       apply_peer(trans, p);
02923       if (!p->sentfullkey)
02924          ast_set_flag(trans, FLAG_SENDFULLKEY);
02925    }
02926    trans->strans = tid;
02927    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02928 
02929    return trans;
02930 }

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

Definition at line 1362 of file pbx_dundi.c.

References ast_aes_decrypt().

Referenced by dundi_decrypt().

01363 {
01364    unsigned char lastblock[16];
01365    int x;
01366    memcpy(lastblock, iv, sizeof(lastblock));
01367    while(len > 0) {
01368       ast_aes_decrypt(src, dst, dcx);
01369       for (x=0;x<16;x++)
01370          dst[x] ^= lastblock[x];
01371       memcpy(lastblock, src, sizeof(lastblock));
01372       dst += 16;
01373       src += 16;
01374       len -= 16;
01375    }
01376    return 0;
01377 }

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

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

01524 {
01525    struct permission *cur, *perm;
01526 
01527    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01528 
01529    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01530    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01531 
01532    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01533       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01534          continue;
01535 
01536       perm->allow = cur->allow;
01537       strcpy(perm->name, cur->name);
01538 
01539       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01540    }
01541 
01542    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01543       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01544          continue;
01545 
01546       perm->allow = cur->allow;
01547       strcpy(perm->name, cur->name);
01548 
01549       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01550    }
01551 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4165 of file pbx_dundi.c.

References ast_free, and map.

Referenced by prune_mappings().

04166 {
04167    if (map->weightstr)
04168       ast_free(map->weightstr);
04169    ast_free(map);
04170 }

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

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

02949 {
02950    if (pack->parent)
02951       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02952    AST_SCHED_DEL(sched, pack->retransid);
02953    if (needfree)
02954       ast_free(pack);
02955 }

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

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

01982 {
01983    struct dundi_packet *pack;
01984 
01985    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01986       AST_SCHED_DEL(sched, pack->retransid);
01987       ast_free(pack);
01988    }
01989 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

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

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

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

Definition at line 4146 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, and permission::list.

Referenced by build_peer(), and destroy_peer().

04147 {
04148    struct permission *perm;
04149 
04150    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04151       ast_free(perm);
04152 }

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

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

02958 {
02959    struct dundi_peer *peer;
02960    int ms;
02961    int x;
02962    int cnt;
02963    char eid_str[20];
02964    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02965       AST_LIST_TRAVERSE(&peers, peer, list) {
02966          if (peer->regtrans == trans)
02967             peer->regtrans = NULL;
02968          if (peer->qualtrans == trans) {
02969             if (fromtimeout) {
02970                if (peer->lastms > -1)
02971                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02972                peer->lastms = -1;
02973             } else {
02974                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02975                if (ms < 1)
02976                   ms = 1;
02977                if (ms < peer->maxms) {
02978                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02979                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02980                } else if (peer->lastms < peer->maxms) {
02981                   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);
02982                }
02983                peer->lastms = ms;
02984             }
02985             peer->qualtrans = NULL;
02986          }
02987          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02988             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02989                if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) {
02990                   peer->avgms = 0;
02991                   cnt = 0;
02992                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02993                      ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02994                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02995                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02996                      peer->lookups[x] = peer->lookups[x-1];
02997                      if (peer->lookups[x]) {
02998                         peer->avgms += peer->lookuptimes[x];
02999                         cnt++;
03000                      }
03001                   }
03002                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
03003                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
03004                   if (peer->lookups[0]) {
03005                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
03006                      peer->avgms += peer->lookuptimes[0];
03007                      cnt++;
03008                   }
03009                   if (cnt)
03010                      peer->avgms /= cnt;
03011                }
03012             }
03013          }
03014       }
03015    }
03016    if (trans->parent) {
03017       /* Unlink from parent if appropriate */
03018       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
03019       if (AST_LIST_EMPTY(&trans->parent->trans)) {
03020          /* Wake up sleeper */
03021          if (trans->parent->pfds[1] > -1) {
03022             if (write(trans->parent->pfds[1], "killa!", 6) < 0) {
03023                ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
03024             }
03025          }
03026       }
03027    }
03028    /* Unlink from all trans */
03029    AST_LIST_REMOVE(&alltrans, trans, all);
03030    destroy_packets(&trans->packets);
03031    destroy_packets(&trans->lasttrans);
03032    AST_SCHED_DEL(sched, trans->autokillid);
03033    if (trans->thread) {
03034       /* If used by a thread, mark as dead and be done */
03035       ast_set_flag(trans, FLAG_DEAD);
03036    } else
03037       ast_free(trans);
03038 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3279 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03280 {
03281    struct dundi_transaction *trans;
03282    AST_LIST_LOCK(&peers);
03283    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03284       dundi_discover(trans);
03285    }
03286    AST_LIST_UNLOCK(&peers);
03287    return 0;
03288 }

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

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

03135 {
03136    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03137    char eid_str[20];
03138    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n",
03139       ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03140    trans->autokillid = -1;
03141    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03142    return 0;
03143 }

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

Definition at line 4317 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04318 {
04319    struct dundi_peer *peer = (struct dundi_peer *)data;
04320    peer->qualifyid = -1;
04321    qualify_peer(peer, 0);
04322    return 0;
04323 }

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

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

04292 {
04293    struct dundi_ie_data ied;
04294    struct dundi_peer *peer = (struct dundi_peer *)data;
04295    char eid_str[20];
04296    char eid_str2[20];
04297    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));
04298    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04299    /* Destroy old transaction if there is one */
04300    if (peer->regtrans)
04301       destroy_trans(peer->regtrans, 0);
04302    peer->regtrans = create_transaction(peer);
04303    if (peer->regtrans) {
04304       ast_set_flag(peer->regtrans, FLAG_ISREG);
04305       memset(&ied, 0, sizeof(ied));
04306       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04307       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04308       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04309       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04310 
04311    } else
04312       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));
04313 
04314    return 0;
04315 }

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

Note:
Called with the peers list already locked

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

01297 {
01298    struct dundi_peer *peer = (struct dundi_peer *)data;
01299    char eid_str[20];
01300    ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01301    peer->registerexpire = -1;
01302    peer->lastms = 0;
01303    memset(&peer->addr, 0, sizeof(peer->addr));
01304    return 0;
01305 }

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3957 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03958 {
03959    ast_free(drds);
03960 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3962 of file pbx_dundi.c.

References drds_destroy().

03963 {
03964    struct dundi_result_datastore *drds = data;
03965    drds_destroy(drds);
03966 }

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

Definition at line 439 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00440 {
00441    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00442 }

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

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

Referenced by handle_command_response().

00787 {
00788    struct dundi_query_state *st;
00789    int totallen;
00790    int x;
00791    int skipfirst=0;
00792    char eid_str[20];
00793    char *s;
00794    pthread_t lookupthread;
00795 
00796    if (ies->eidcount > 1) {
00797       /* Since it is a requirement that the first EID is the authenticating host
00798          and the last EID is the root, it is permissible that the first and last EID
00799          could be the same.  In that case, we should go ahead copy only the "root" section
00800          since we will not need it for authentication. */
00801       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00802          skipfirst = 1;
00803    }
00804    totallen = sizeof(struct dundi_query_state);
00805    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00806    st = ast_calloc(1, totallen);
00807    if (st) {
00808       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00809       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00810       st->trans = trans;
00811       st->ttl = ies->ttl - 1;
00812       if (st->ttl < 0)
00813          st->ttl = 0;
00814       s = st->fluffy;
00815       for (x=skipfirst;ies->eids[x];x++) {
00816          st->eids[x-skipfirst] = (dundi_eid *)s;
00817          *st->eids[x-skipfirst] = *ies->eids[x];
00818          s += sizeof(dundi_eid);
00819       }
00820       ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00821 
00822       trans->thread = 1;
00823       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
00824          struct dundi_ie_data ied = { 0, };
00825          trans->thread = 0;
00826          ast_log(LOG_WARNING, "Unable to create thread!\n");
00827          ast_free(st);
00828          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00829          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00830          return -1;
00831       }
00832    } else {
00833       struct dundi_ie_data ied = { 0, };
00834       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00835       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00836       return -1;
00837    }
00838    return 0;
00839 }

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

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

Referenced by handle_command_response().

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

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04565 {
04566    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04567 }

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

Definition at line 346 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

00347 {
00348    if (dundidebug)
00349       ast_verbose("%s", data);
00350 }

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

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

01380 {
01381    int space = *dstlen;
01382    unsigned long bytes;
01383    struct dundi_hdr *h;
01384    unsigned char *decrypt_space;
01385    decrypt_space = alloca(srclen);
01386    if (!decrypt_space)
01387       return NULL;
01388    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01389    /* Setup header */
01390    h = (struct dundi_hdr *)dst;
01391    *h = *ohdr;
01392    bytes = space - 6;
01393    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01394       ast_debug(1, "Ouch, uncompress failed :(\n");
01395       return NULL;
01396    }
01397    /* Update length */
01398    *dstlen = bytes + 6;
01399    /* Return new header */
01400    return h;
01401 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

03168 {
03169    struct dundi_ie_data ied;
03170    int x;
03171    if (!trans->parent) {
03172       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03173       return -1;
03174    }
03175    memset(&ied, 0, sizeof(ied));
03176    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03177    if (!dundi_eid_zero(&trans->us_eid))
03178       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03179    for (x=0;x<trans->eidcount;x++)
03180       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03181    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03182    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03183    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03184    if (trans->parent->cbypass)
03185       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03186    if (trans->autokilltimeout)
03187       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03188    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03189 }

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

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

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

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

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

02477 {
02478    int res;
02479    char tmp[256];
02480    char *context;
02481    struct timeval start;
02482    switch (cmd) {
02483    case CLI_INIT:
02484       e->command = "dundi precache";
02485       e->usage =
02486          "Usage: dundi precache <number>[@context]\n"
02487          "       Lookup the given number within the given DUNDi context\n"
02488          "(or e164 if none is specified) and precaches the results to any\n"
02489          "upstream DUNDi push servers.\n";
02490       return NULL;
02491    case CLI_GENERATE:
02492       return NULL;
02493    }
02494    if ((a->argc < 3) || (a->argc > 3))
02495       return CLI_SHOWUSAGE;
02496    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02497    context = strchr(tmp, '@');
02498    if (context) {
02499       *context = '\0';
02500       context++;
02501    }
02502    start = ast_tvnow();
02503    res = dundi_precache(context, tmp);
02504 
02505    if (res < 0)
02506       ast_cli(a->fd, "DUNDi precache returned error.\n");
02507    else if (!res)
02508       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02509    ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02510    return CLI_SUCCESS;
02511 }

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

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

02514 {
02515    int res;
02516    char tmp[256];
02517    char *context;
02518    dundi_eid eid;
02519    struct dundi_entity_info dei;
02520    switch (cmd) {
02521    case CLI_INIT:
02522       e->command = "dundi query";
02523       e->usage =
02524          "Usage: dundi query <entity>[@context]\n"
02525          "       Attempts to retrieve contact information for a specific\n"
02526          "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
02527          "e164 if none is specified).\n";
02528       return NULL;
02529    case CLI_GENERATE:
02530       return NULL;
02531    }
02532    if ((a->argc < 3) || (a->argc > 3))
02533       return CLI_SHOWUSAGE;
02534    if (ast_str_to_eid(&eid, a->argv[2])) {
02535       ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
02536       return CLI_SHOWUSAGE;
02537    }
02538    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02539    context = strchr(tmp, '@');
02540    if (context) {
02541       *context = '\0';
02542       context++;
02543    }
02544    res = dundi_query_eid(&dei, context, eid);
02545    if (res < 0)
02546       ast_cli(a->fd, "DUNDi Query EID returned error.\n");
02547    else if (!res)
02548       ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
02549    else {
02550       ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
02551       ast_cli(a->fd, "Department:      %s\n", dei.orgunit);
02552       ast_cli(a->fd, "Organization:    %s\n", dei.org);
02553       ast_cli(a->fd, "City/Locality:   %s\n", dei.locality);
02554       ast_cli(a->fd, "State/Province:  %s\n", dei.stateprov);
02555       ast_cli(a->fd, "Country:         %s\n", dei.country);
02556       ast_cli(a->fd, "E-mail:          %s\n", dei.email);
02557       ast_cli(a->fd, "Phone:           %s\n", dei.phone);
02558       ast_cli(a->fd, "IP Address:      %s\n", dei.ipaddr);
02559    }
02560    return CLI_SUCCESS;
02561 }

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

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

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

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

Definition at line 352 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00353 {
00354    ast_log(LOG_WARNING, "%s", data);
00355 }

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

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

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

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

02325 {
02326    int stats = 0;
02327    switch (cmd) {
02328    case CLI_INIT:
02329       e->command = "dundi flush [stats]";
02330       e->usage =
02331          "Usage: dundi flush [stats]\n"
02332          "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
02333          "'stats' is present, clears timer statistics instead of normal\n"
02334          "operation.\n";
02335       return NULL;
02336    case CLI_GENERATE:
02337       return NULL;
02338    }
02339    if ((a->argc < 2) || (a->argc > 3))
02340       return CLI_SHOWUSAGE;
02341    if (a->argc > 2) {
02342       if (!strcasecmp(a->argv[2], "stats"))
02343          stats = 1;
02344       else
02345          return CLI_SHOWUSAGE;
02346    }
02347    if (stats) {
02348       /* Flush statistics */
02349       struct dundi_peer *p;
02350       int x;
02351       AST_LIST_LOCK(&peers);
02352       AST_LIST_TRAVERSE(&peers, p, list) {
02353          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02354             if (p->lookups[x])
02355                ast_free(p->lookups[x]);
02356             p->lookups[x] = NULL;
02357             p->lookuptimes[x] = 0;
02358          }
02359          p->avgms = 0;
02360       }
02361       AST_LIST_UNLOCK(&peers);
02362    } else {
02363       ast_db_deltree("dundi/cache", NULL);
02364       ast_cli(a->fd, "DUNDi Cache Flushed\n");
02365    }
02366    return CLI_SUCCESS;
02367 }

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

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

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

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

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

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

03146 {
03147    struct dundi_peer *p;
03148    if (!ast_eid_cmp(eid, us)) {
03149       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03150       return;
03151    }
03152    AST_LIST_LOCK(&peers);
03153    AST_LIST_TRAVERSE(&peers, p, list) {
03154       if (!ast_eid_cmp(&p->eid, eid)) {
03155          if (has_permission(&p->include, context))
03156             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03157          else
03158             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03159          break;
03160       }
03161    }
03162    if (!p)
03163       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03164    AST_LIST_UNLOCK(&peers);
03165 }

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

References DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, and dundi_lookup_internal().

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

03678 {
03679    struct dundi_hint_metadata hmd;
03680    dundi_eid *avoid[1] = { NULL, };
03681    int direct[1] = { 0, };
03682    int expiration = dundi_cache_time;
03683    memset(&hmd, 0, sizeof(hmd));
03684    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03685    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03686 }

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

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

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

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

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

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

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

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04625 {
04626    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04627 }

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

Pre-cache to push upstream peers.

Definition at line 3821 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03822 {
03823    dundi_eid *avoid[1] = { NULL, };
03824    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03825 }

static void dundi_precache_full ( void   )  [static]

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

03725 {
03726    struct dundi_mapping *cur;
03727    struct ast_context *con;
03728    struct ast_exten *e;
03729 
03730    AST_LIST_TRAVERSE(&mappings, cur, list) {
03731       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03732       ast_rdlock_contexts();
03733       con = NULL;
03734       while ((con = ast_walk_contexts(con))) {
03735          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03736             continue;
03737          /* Found the match, now queue them all up */
03738          ast_rdlock_context(con);
03739          e = NULL;
03740          while ((e = ast_walk_context_extensions(con, e)))
03741             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03742          ast_unlock_context(con);
03743       }
03744       ast_unlock_contexts();
03745    }
03746 }

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

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

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

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

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

00699 {
00700    struct dundi_query_state *st = data;
00701    struct dundi_ie_data ied;
00702    struct dundi_hint_metadata hmd;
00703    char eid_str[20];
00704 
00705    ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
00706       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00707    memset(&ied, 0, sizeof(ied));
00708 
00709    /* Now produce precache */
00710    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00711 
00712    AST_LIST_LOCK(&peers);
00713    /* Truncate if "don't ask" isn't present */
00714    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00715       hmd.exten[0] = '\0';
00716    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00717       ast_debug(1, "Our transaction went away!\n");
00718       st->trans->thread = 0;
00719       destroy_trans(st->trans, 0);
00720    } else {
00721       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00722       st->trans->thread = 0;
00723    }
00724    AST_LIST_UNLOCK(&peers);
00725    ast_free(st);
00726    return NULL;
00727 }

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

Definition at line 917 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, tech2str(), dundi_result::techint, dundi_result::weight, and dundi_answer::weight.

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

03258 {
03259    struct dundi_ie_data ied;
03260    int x;
03261    if (!trans->parent) {
03262       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03263       return -1;
03264    }
03265    memset(&ied, 0, sizeof(ied));
03266    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03267    if (!dundi_eid_zero(&trans->us_eid))
03268       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03269    for (x=0;x<trans->eidcount;x++)
03270       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03271    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03272    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03273    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03274    if (trans->autokilltimeout)
03275       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03276    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03277 }

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

Retrieve information on a specific EID.

Definition at line 3874 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03875 {
03876    dundi_eid *avoid[1] = { NULL, };
03877    struct dundi_hint_metadata hmd;
03878    memset(&hmd, 0, sizeof(hmd));
03879    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03880 }

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

03828 {
03829    int res;
03830    struct dundi_request dr;
03831    dundi_eid *rooteid=NULL;
03832    int x;
03833    int ttlms;
03834    int skipped=0;
03835    int foundcache=0;
03836    struct timeval start;
03837 
03838    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03839 
03840    for (x=0;avoid[x];x++)
03841       rooteid = avoid[x];
03842    /* Now perform real check */
03843    memset(&dr, 0, sizeof(dr));
03844    dr.hmd = hmd;
03845    dr.dei = dei;
03846    dr.pfds[0] = dr.pfds[1] = -1;
03847    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03848    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03849    if (rooteid)
03850       dr.root_eid = *rooteid;
03851    /* Create transactions */
03852    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03853 
03854    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03855       do this earlier because we didn't know if we were going to have transactions
03856       or not. */
03857    if (!ttl) {
03858       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03859       return 0;
03860    }
03861 
03862    /* Optimize transactions */
03863    optimize_transactions(&dr, 9999);
03864    /* Actually perform transactions */
03865    query_transactions(&dr);
03866    /* Wait for transaction to come back */
03867    start = ast_tvnow();
03868    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03869       usleep(1);
03870    res = dr.respcount;
03871    return res;
03872 }

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

Definition at line 3973 of file pbx_dundi.c.

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

03974 {
03975    struct ast_module_user *u;
03976    AST_DECLARE_APP_ARGS(args,
03977       AST_APP_ARG(number);
03978       AST_APP_ARG(context);
03979       AST_APP_ARG(options);
03980    );
03981    struct ast_flags opts = { 0, };
03982    char *parse;
03983    struct dundi_result_datastore *drds;
03984    struct ast_datastore *datastore;
03985 
03986    u = ast_module_user_add(chan);
03987 
03988    if (ast_strlen_zero(data)) {
03989       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
03990       ast_module_user_remove(u);
03991       return -1;
03992    }
03993 
03994    if (!chan) {
03995       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
03996       ast_module_user_remove(u);
03997       return -1;
03998    }
03999 
04000    parse = ast_strdupa(data);
04001 
04002    AST_STANDARD_APP_ARGS(args, parse);
04003 
04004    if (!ast_strlen_zero(args.options))
04005       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
04006 
04007    if (ast_strlen_zero(args.context))
04008       args.context = "e164";
04009 
04010    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
04011       ast_module_user_remove(u);
04012       return -1;
04013    }
04014 
04015    drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
04016    snprintf(buf, len, "%u", drds->id);
04017 
04018    if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) {
04019       drds_destroy(drds);
04020       ast_module_user_remove(u);
04021       return -1;
04022    }
04023 
04024    datastore->data = drds;
04025 
04026    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context,
04027       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04028 
04029    if (drds->num_results > 0)
04030       sort_results(drds->results, drds->num_results);
04031 
04032    ast_channel_lock(chan);
04033    ast_channel_datastore_add(chan, datastore);
04034    ast_channel_unlock(chan);
04035 
04036    ast_module_user_remove(u);
04037 
04038    return 0;
04039 }

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

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

00732 {
00733    struct dundi_query_state *st = data;
00734    struct dundi_entity_info dei;
00735    struct dundi_ie_data ied;
00736    struct dundi_hint_metadata hmd;
00737    char eid_str[20];
00738    int res;
00739 
00740    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00741       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00742    memset(&ied, 0, sizeof(ied));
00743    memset(&dei, 0, sizeof(dei));
00744    memset(&hmd, 0, sizeof(hmd));
00745    if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00746       /* Ooh, it's us! */
00747       ast_debug(1, "Neat, someone look for us!\n");
00748       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00749       ast_copy_string(dei.org, org, sizeof(dei.org));
00750       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00751       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00752       ast_copy_string(dei.country, country, sizeof(dei.country));
00753       ast_copy_string(dei.email, email, sizeof(dei.email));
00754       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00755       res = 1;
00756    } else {
00757       /* If we do not have a canonical result, keep looking */
00758       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00759    }
00760    AST_LIST_LOCK(&peers);
00761    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00762       ast_debug(1, "Our transaction went away!\n");
00763       st->trans->thread = 0;
00764       destroy_trans(st->trans, 0);
00765    } else {
00766       if (res) {
00767          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00768          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00769          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00770          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00771          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00772          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00773          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00774          if (!ast_strlen_zero(dei.ipaddr))
00775             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00776       }
00777       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00778       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00779       st->trans->thread = 0;
00780    }
00781    AST_LIST_UNLOCK(&peers);
00782    ast_free(st);
00783    return NULL;
00784 }

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

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

00444 {
00445    struct {
00446       struct dundi_packet pack;
00447       struct dundi_hdr hdr;
00448    } tmp;
00449    struct dundi_transaction trans;
00450    /* Never respond to an INVALID with another INVALID */
00451    if (h->cmdresp == DUNDI_COMMAND_INVALID)
00452       return;
00453    memset(&tmp, 0, sizeof(tmp));
00454    memset(&trans, 0, sizeof(trans));
00455    memcpy(&trans.addr, sin, sizeof(trans.addr));
00456    tmp.hdr.strans = h->dtrans;
00457    tmp.hdr.dtrans = h->strans;
00458    tmp.hdr.iseqno = h->oseqno;
00459    tmp.hdr.oseqno = h->iseqno;
00460    tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00461    tmp.hdr.cmdflags = 0;
00462    tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00463    tmp.pack.datalen = sizeof(struct dundi_hdr);
00464    tmp.pack.parent = &trans;
00465    dundi_xmit(&tmp.pack);
00466 }

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

Definition at line 4046 of file pbx_dundi.c.

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

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

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

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

03041 {
03042    struct dundi_packet *pack = (struct dundi_packet *)data;
03043    int res;
03044    AST_LIST_LOCK(&peers);
03045    if (pack->retrans < 1) {
03046       pack->retransid = -1;
03047       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
03048          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",
03049             ast_inet_ntoa(pack->parent->addr.sin_addr),
03050             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
03051       destroy_trans(pack->parent, 1);
03052       res = 0;
03053    } else {
03054       /* Decrement retransmission, try again */
03055       pack->retrans--;
03056       dundi_xmit(pack);
03057       res = 1;
03058    }
03059    AST_LIST_UNLOCK(&peers);
03060    return res;
03061 }

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

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

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

static char* dundi_set_debug ( 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 set debug {on|off}";
02276       e->usage =
02277          "Usage: dundi set debug {on|off}\n"
02278          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02279       return NULL;
02280    case CLI_GENERATE:
02281       return NULL;
02282    }
02283 
02284    if (a->argc != e->args)
02285       return CLI_SHOWUSAGE;
02286 
02287    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02288       dundidebug = 1;
02289       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02290    } else {
02291       dundidebug = 0;
02292       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02293    }
02294    return CLI_SUCCESS;
02295 }

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

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

02762 {
02763    char eid_str[20];
02764    switch (cmd) {
02765    case CLI_INIT:
02766       e->command = "dundi show entityid";
02767       e->usage =
02768          "Usage: dundi show entityid\n"
02769          "       Displays the global entityid for this host.\n";
02770       return NULL;
02771    case CLI_GENERATE:
02772       return NULL;
02773    }
02774    if (a->argc != 3)
02775       return CLI_SHOWUSAGE;
02776    AST_LIST_LOCK(&peers);
02777    ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02778    AST_LIST_UNLOCK(&peers);
02779    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02780    return CLI_SUCCESS;
02781 }

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

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

02816 {
02817 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02818 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02819    struct dundi_mapping *map;
02820    char fs[256];
02821    char weight[8];
02822    switch (cmd) {
02823    case CLI_INIT:
02824       e->command = "dundi show mappings";
02825       e->usage =
02826          "Usage: dundi show mappings\n"
02827          "       Lists all known DUNDi mappings.\n";
02828       return NULL;
02829    case CLI_GENERATE:
02830       return NULL;
02831    }
02832    if (a->argc != 3)
02833       return CLI_SHOWUSAGE;
02834    AST_LIST_LOCK(&peers);
02835    ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02836    AST_LIST_TRAVERSE(&mappings, map, list) {
02837       snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map));
02838       ast_cli(a->fd, FORMAT, map->dcontext, weight,
02839          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext,
02840          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02841    }
02842    AST_LIST_UNLOCK(&peers);
02843    return CLI_SUCCESS;
02844 #undef FORMAT
02845 #undef FORMAT2
02846 }

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

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

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

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

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

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

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

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

02849 {
02850 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02851 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02852    struct dundi_precache_queue *qe;
02853    int h,m,s;
02854    time_t now;
02855    switch (cmd) {
02856    case CLI_INIT:
02857       e->command = "dundi show precache";
02858       e->usage =
02859          "Usage: dundi show precache\n"
02860          "       Lists all known DUNDi scheduled precache updates.\n";
02861       return NULL;
02862    case CLI_GENERATE:
02863       return NULL;
02864    }
02865    if (a->argc != 3)
02866       return CLI_SHOWUSAGE;
02867    time(&now);
02868    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
02869    AST_LIST_LOCK(&pcq);
02870    AST_LIST_TRAVERSE(&pcq, qe, list) {
02871       s = qe->expiration - now;
02872       h = s / 3600;
02873       s = s % 3600;
02874       m = s / 60;
02875       s = s % 60;
02876       ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
02877    }
02878    AST_LIST_UNLOCK(&pcq);
02879 
02880    return CLI_SUCCESS;
02881 #undef FORMAT
02882 #undef FORMAT2
02883 }

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

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

02784 {
02785 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02786 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02787    struct dundi_request *req;
02788    char eidstr[20];
02789    switch (cmd) {
02790    case CLI_INIT:
02791       e->command = "dundi show requests";
02792       e->usage =
02793          "Usage: dundi show requests\n"
02794          "       Lists all known pending DUNDi requests.\n";
02795       return NULL;
02796    case CLI_GENERATE:
02797       return NULL;
02798    }
02799    if (a->argc != 3)
02800       return CLI_SHOWUSAGE;
02801    AST_LIST_LOCK(&peers);
02802    ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02803    AST_LIST_TRAVERSE(&requests, req, list) {
02804       ast_cli(a->fd, FORMAT, req->number, req->dcontext,
02805          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02806    }
02807    AST_LIST_UNLOCK(&peers);
02808    return CLI_SUCCESS;
02809 #undef FORMAT
02810 #undef FORMAT2
02811 }

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

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

02733 {
02734 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02735 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02736    struct dundi_transaction *trans;
02737    switch (cmd) {
02738    case CLI_INIT:
02739       e->command = "dundi show trans";
02740       e->usage =
02741          "Usage: dundi show trans\n"
02742          "       Lists all known DUNDi transactions.\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_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02751    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02752       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),
02753          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02754    }
02755    AST_LIST_UNLOCK(&peers);
02756    return CLI_SUCCESS;
02757 #undef FORMAT
02758 #undef FORMAT2
02759 }

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

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

02298 {
02299    switch (cmd) {
02300    case CLI_INIT:
02301       e->command = "dundi store history {on|off}";
02302       e->usage =
02303          "Usage: dundi store history {on|off}\n"
02304          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02305          "purposes\n";
02306       return NULL;
02307    case CLI_GENERATE:
02308       return NULL;
02309    }
02310 
02311    if (a->argc != e->args)
02312       return CLI_SHOWUSAGE;
02313 
02314    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02315       global_storehistory = 1;
02316       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02317    } else {
02318       global_storehistory = 0;
02319       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02320    }
02321    return CLI_SUCCESS;
02322 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02933 {
02934    int res;
02935    if (dundidebug)
02936       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02937    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02938    if (res < 0) {
02939       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",
02940          ast_inet_ntoa(pack->parent->addr.sin_addr),
02941          ntohs(pack->parent->addr.sin_port), strerror(errno));
02942    }
02943    if (res > 0)
02944       res = 0;
02945    return res;
02946 }

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

Definition at line 3890 of file pbx_dundi.c.

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

03891 {
03892    int results;
03893    int x;
03894    struct ast_module_user *u;
03895    struct dundi_result dr[MAX_RESULTS];
03896    AST_DECLARE_APP_ARGS(args,
03897       AST_APP_ARG(number);
03898       AST_APP_ARG(context);
03899       AST_APP_ARG(options);
03900    );
03901    char *parse;
03902    struct ast_flags opts = { 0, };
03903 
03904    buf[0] = '\0';
03905 
03906    if (ast_strlen_zero(num)) {
03907       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03908       return -1;
03909    }
03910 
03911    u = ast_module_user_add(chan);
03912 
03913    parse = ast_strdupa(num);
03914 
03915    AST_STANDARD_APP_ARGS(args, parse);
03916 
03917    if (!ast_strlen_zero(args.options)) {
03918       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03919    }
03920    if (ast_strlen_zero(args.context)) {
03921       args.context = "e164";
03922    }
03923 
03924    results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
03925    if (results > 0) {
03926       sort_results(dr, results);
03927       for (x = 0; x < results; x++) {
03928          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03929             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03930             break;
03931          }
03932       }
03933    }
03934 
03935    ast_module_user_remove(u);
03936 
03937    return 0;
03938 }

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

Definition at line 1346 of file pbx_dundi.c.

References ast_aes_encrypt().

Referenced by dundi_encrypt().

01347 {
01348    unsigned char curblock[16];
01349    int x;
01350    memcpy(curblock, iv, sizeof(curblock));
01351    while(len > 0) {
01352       for (x=0;x<16;x++)
01353          curblock[x] ^= src[x];
01354       ast_aes_encrypt(curblock, dst, ecx);
01355       memcpy(curblock, dst, sizeof(curblock));
01356       dst += 16;
01357       src += 16;
01358       len -= 16;
01359    }
01360    return 0;
01361 }

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

Definition at line 503 of file pbx_dundi.c.

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

00504 {
00505    struct dundi_peer *cur = NULL;
00506 
00507    if (!eid)
00508       eid = &empty_eid;
00509 
00510    AST_LIST_TRAVERSE(&peers, cur, list) {
00511       if (!ast_eid_cmp(&cur->eid,eid))
00512          break;
00513    }
00514 
00515    if (!cur && any_peer)
00516       cur = any_peer;
00517 
00518    return cur;
00519 }

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

Definition at line 401 of file pbx_dundi.c.

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

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

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

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 547 of file pbx_dundi.c.

References map, MAX_WEIGHT, and pbx_substitute_variables_helper().

Referenced by dundi_lookup_local(), and dundi_show_mappings().

00548 {
00549    char buf[32];
00550 
00551    buf[0] = 0;
00552    if (map->weightstr) {
00553       pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
00554       if (sscanf(buf, "%30d", &map->_weight) != 1)
00555          map->_weight = MAX_WEIGHT;
00556    }
00557 
00558    return map->_weight;
00559 }

static int get_trans_id ( void   )  [static]

Definition at line 468 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

00469 {
00470    struct dundi_transaction *t;
00471    int stid = (ast_random() % 32766) + 1;
00472    int tid = stid;
00473 
00474    do {
00475       AST_LIST_TRAVERSE(&alltrans, t, all) {
00476          if (t->strans == tid)
00477             break;
00478       }
00479       if (!t)
00480          return tid;
00481       tid = (tid % 32766) + 1;
00482    } while (tid != stid);
00483 
00484    return 0;
00485 }

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

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

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

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

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

02014 {
02015    struct dundi_transaction *trans;
02016    trans = find_transaction(h, sin);
02017    if (!trans) {
02018       dundi_reject(h, sin);
02019       return 0;
02020    }
02021    /* Got a transaction, see where this header fits in */
02022    if (h->oseqno == trans->iseqno) {
02023       /* Just what we were looking for...  Anything but ack increments iseqno */
02024       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
02025          /* If final, we're done */
02026          destroy_trans(trans, 0);
02027          return 0;
02028       }
02029       if (h->cmdresp != DUNDI_COMMAND_ACK) {
02030          trans->oiseqno = trans->iseqno;
02031          trans->iseqno++;
02032          handle_command_response(trans, h, datalen, 0);
02033       }
02034       if (trans->aseqno != trans->iseqno) {
02035          dundi_ack(trans, h->cmdresp & 0x80);
02036          trans->aseqno = trans->iseqno;
02037       }
02038       /* Delete any saved last transmissions */
02039       destroy_packets(&trans->lasttrans);
02040       if (h->cmdresp & 0x80) {
02041          /* Final -- destroy now */
02042          destroy_trans(trans, 0);
02043       }
02044    } else if (h->oseqno == trans->oiseqno) {
02045       /* Last incoming sequence number -- send ACK without processing */
02046       dundi_ack(trans, 0);
02047    } else {
02048       /* Out of window -- simply drop */
02049       ast_debug(1, "Dropping packet out of window!\n");
02050    }
02051    return 0;
02052 }

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

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

00358 {
00359    struct permission *perm;
00360    int res = 0;
00361 
00362    AST_LIST_TRAVERSE(permlist, perm, list) {
00363       if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
00364          res = perm->allow;
00365    }
00366 
00367    return res;
00368 }

static int load_module ( void   )  [static]

Definition at line 4826 of file pbx_dundi.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_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().

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

static void load_password ( void   )  [static]

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

02111 {
02112    char *current=NULL;
02113    char *last=NULL;
02114    char tmp[256];
02115    time_t expired;
02116 
02117    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02118    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02119       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02120       current = strchr(tmp, ';');
02121       if (!current)
02122          current = tmp;
02123       else {
02124          *current = '\0';
02125          current++;
02126       };
02127       if ((time(NULL) - expired) < 0) {
02128          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02129             expired = time(NULL) + DUNDI_SECRET_TIME;
02130       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02131          last = current;
02132          current = NULL;
02133       } else {
02134          last = NULL;
02135          current = NULL;
02136       }
02137    }
02138    if (current) {
02139       /* Current key is still valid, just setup rotatation properly */
02140       ast_copy_string(cursecret, current, sizeof(cursecret));
02141       rotatetime = expired;
02142    } else {
02143       /* Current key is out of date, rotate or eliminate all together */
02144       build_secret(cursecret, sizeof(cursecret));
02145       save_secret(cursecret, last);
02146    }
02147 }

static void mark_mappings ( void   )  [static]

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

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

static void mark_peers ( void   )  [static]

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

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

static char* model2str ( int  model  )  [static]

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

02370 {
02371    switch(model) {
02372    case DUNDI_MODEL_INBOUND:
02373       return "Inbound";
02374    case DUNDI_MODEL_OUTBOUND:
02375       return "Outbound";
02376    case DUNDI_MODEL_SYMMETRIC:
02377       return "Symmetric";
02378    default:
02379       return "Unknown";
02380    }
02381 }

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

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

02167 {
02168    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames
02169       from the network, and queue them for delivery to the channels */
02170    int res;
02171    /* Establish I/O callback for socket read */
02172    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02173 
02174    while (!dundi_shutdown) {
02175       res = ast_sched_wait(sched);
02176       if ((res > 1000) || (res < 0))
02177          res = 1000;
02178       res = ast_io_wait(io, res);
02179       if (res >= 0) {
02180          AST_LIST_LOCK(&peers);
02181          ast_sched_runq(sched);
02182          AST_LIST_UNLOCK(&peers);
02183       }
02184       check_password();
02185    }
02186 
02187    netthreadid = AST_PTHREADT_NULL;
02188 
02189    return NULL;
02190 }

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

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

03339 {
03340    /* Minimize the message propagation through DUNDi by
03341       alerting the network to hops which should be not be considered */
03342    struct dundi_transaction *trans;
03343    struct dundi_peer *peer;
03344    dundi_eid tmp;
03345    int x;
03346    int needpush;
03347 
03348    AST_LIST_LOCK(&peers);
03349    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03350       /* Pop off the true root */
03351       if (trans->eidcount) {
03352          tmp = trans->eids[--trans->eidcount];
03353          needpush = 1;
03354       } else {
03355          tmp = trans->us_eid;
03356          needpush = 0;
03357       }
03358 
03359       AST_LIST_TRAVERSE(&peers, peer, list) {
03360          if (has_permission(&peer->include, dr->dcontext) &&
03361              ast_eid_cmp(&peer->eid, &trans->them_eid) &&
03362             (peer->order <= order)) {
03363             /* For each other transaction, make sure we don't
03364                ask this EID about the others if they're not
03365                already in the list */
03366             if (!ast_eid_cmp(&tmp, &peer->eid))
03367                x = -1;
03368             else {
03369                for (x=0;x<trans->eidcount;x++) {
03370                   if (!ast_eid_cmp(&trans->eids[x], &peer->eid))
03371                      break;
03372                }
03373             }
03374             if (x == trans->eidcount) {
03375                /* Nope not in the list, if needed, add us at the end since we're the source */
03376                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03377                   trans->eids[trans->eidcount++] = peer->eid;
03378                   /* Need to insert the real root (or us) at the bottom now as
03379                      a requirement now.  */
03380                   needpush = 1;
03381                }
03382             }
03383          }
03384       }
03385       /* If necessary, push the true root back on the end */
03386       if (needpush)
03387          trans->eids[trans->eidcount++] = tmp;
03388    }
03389    AST_LIST_UNLOCK(&peers);
03390 
03391    return 0;
03392 }

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

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

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

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

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

03192 {
03193    struct dundi_ie_data ied;
03194    int x, res;
03195    int max = 999999;
03196    int expiration = dundi_cache_time;
03197    int ouranswers=0;
03198    dundi_eid *avoid[1] = { NULL, };
03199    int direct[1] = { 0, };
03200    struct dundi_result dr[MAX_RESULTS];
03201    struct dundi_hint_metadata hmd;
03202    if (!trans->parent) {
03203       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03204       return -1;
03205    }
03206    memset(&hmd, 0, sizeof(hmd));
03207    memset(&dr, 0, sizeof(dr));
03208    /* Look up the answers we're going to include */
03209    for (x=0;x<mapcount;x++)
03210       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03211    if (ouranswers < 0)
03212       ouranswers = 0;
03213    for (x=0;x<ouranswers;x++) {
03214       if (dr[x].weight < max)
03215          max = dr[x].weight;
03216    }
03217    if (max) {
03218       /* If we do not have a canonical result, keep looking */
03219       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);
03220       if (res > 0) {
03221          /* Append answer in result */
03222          ouranswers += res;
03223       }
03224    }
03225 
03226    if (ouranswers > 0) {
03227       *foundanswers += ouranswers;
03228       memset(&ied, 0, sizeof(ied));
03229       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03230       if (!dundi_eid_zero(&trans->us_eid))
03231          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03232       for (x=0;x<trans->eidcount;x++)
03233          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03234       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03235       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03236       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03237       for (x=0;x<ouranswers;x++) {
03238          /* Add answers */
03239          if (dr[x].expiration && (expiration > dr[x].expiration))
03240             expiration = dr[x].expiration;
03241          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03242       }
03243       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03244       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03245       if (trans->autokilltimeout)
03246          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03247       if (expiration < *minexp)
03248          *minexp = expiration;
03249       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03250    } else {
03251       /* Oops, nothing to send... */
03252       destroy_trans(trans, 0);
03253       return 0;
03254    }
03255 }

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

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

03291 {
03292    struct dundi_transaction *trans;
03293 
03294    /* Mark all as "in thread" so they don't disappear */
03295    AST_LIST_LOCK(&peers);
03296    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03297       if (trans->thread)
03298          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03299       trans->thread = 1;
03300    }
03301    AST_LIST_UNLOCK(&peers);
03302 
03303    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03304       if (!ast_test_flag(trans, FLAG_DEAD))
03305          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03306    }
03307 
03308    /* Cleanup any that got destroyed in the mean time */
03309    AST_LIST_LOCK(&peers);
03310    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03311       trans->thread = 0;
03312       if (ast_test_flag(trans, FLAG_DEAD)) {
03313          ast_debug(1, "Our transaction went away!\n");
03314          /* This is going to remove the transaction from the dundi_request's list, as well
03315           * as the global transactions list */
03316          destroy_trans(trans, 0);
03317       }
03318    }
03319    AST_LIST_TRAVERSE_SAFE_END
03320    AST_LIST_UNLOCK(&peers);
03321 
03322    return 0;
03323 }

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

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

02193 {
02194    struct ast_db_entry *db_entry, *db_tree;
02195    int striplen = sizeof("/dundi/cache");
02196    time_t now;
02197 
02198    while (!dundi_shutdown) {
02199       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
02200 
02201       time(&now);
02202 
02203       db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
02204       for (; db_entry; db_entry = db_entry->next) {
02205          time_t expiry;
02206 
02207          if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
02208             if (expiry < now) {
02209                ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
02210                ast_db_del("dundi/cache", db_entry->key + striplen);
02211             }
02212          }
02213       }
02214       ast_db_freetree(db_tree);
02215 
02216       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
02217       pthread_testcancel();
02218       sleep(60);
02219       pthread_testcancel();
02220    }
02221 
02222    clearcachethreadid = AST_PTHREADT_NULL;
02223    return NULL;
02224 }

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

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

02227 {
02228    struct dundi_precache_queue *qe;
02229    time_t now;
02230    char context[256];
02231    char number[256];
02232    int run;
02233 
02234    while (!dundi_shutdown) {
02235       time(&now);
02236       run = 0;
02237       AST_LIST_LOCK(&pcq);
02238       if ((qe = AST_LIST_FIRST(&pcq))) {
02239          if (!qe->expiration) {
02240             /* Gone...  Remove... */
02241             AST_LIST_REMOVE_HEAD(&pcq, list);
02242             ast_free(qe);
02243          } else if (qe->expiration < now) {
02244             /* Process this entry */
02245             qe->expiration = 0;
02246             ast_copy_string(context, qe->context, sizeof(context));
02247             ast_copy_string(number, qe->number, sizeof(number));
02248             run = 1;
02249          }
02250       }
02251       AST_LIST_UNLOCK(&pcq);
02252       if (run) {
02253          dundi_precache(context, number);
02254       } else
02255          sleep(1);
02256    }
02257 
02258    precachethreadid = AST_PTHREADT_NULL;
02259 
02260    return NULL;
02261 }

static void prune_mappings ( void   )  [static]

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

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

static void prune_peers ( void   )  [static]

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

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

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

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

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

static int query_transactions ( struct dundi_request dr  )  [static]

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

03326 {
03327    struct dundi_transaction *trans;
03328 
03329    AST_LIST_LOCK(&peers);
03330    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03331       dundi_query(trans);
03332    }
03333    AST_LIST_UNLOCK(&peers);
03334 
03335    return 0;
03336 }

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

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

03510 {
03511    struct dundi_request *cur;
03512    int res=0;
03513    char eid_str[20];
03514    AST_LIST_LOCK(&peers);
03515    AST_LIST_TRAVERSE(&requests, cur, list) {
03516       ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03517          dr->dcontext, dr->number);
03518       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03519           !strcasecmp(cur->number, dr->number) &&
03520           (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03521          ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n",
03522             cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03523          *pending = cur;
03524          res = 1;
03525          break;
03526       }
03527    }
03528    if (!res) {
03529       ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n",
03530             dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03531       /* Go ahead and link us in since nobody else is searching for this */
03532       AST_LIST_INSERT_HEAD(&requests, dr, list);
03533       *pending = NULL;
03534    }
03535    AST_LIST_UNLOCK(&peers);
03536    return res;
03537 }

static int reload ( void   )  [static]

Definition at line 4816 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04817 {
04818    struct sockaddr_in sin;
04819 
04820    if (set_config("dundi.conf", &sin, 1))
04821       return AST_MODULE_LOAD_FAILURE;
04822 
04823    return AST_MODULE_LOAD_SUCCESS;
04824 }

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

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

03689 {
03690    int len;
03691    struct dundi_precache_queue *qe, *prev;
03692 
03693    AST_LIST_LOCK(&pcq);
03694    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03695       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03696          AST_LIST_REMOVE_CURRENT(list);
03697          break;
03698       }
03699    }
03700    AST_LIST_TRAVERSE_SAFE_END;
03701    if (!qe) {
03702       len = sizeof(*qe);
03703       len += strlen(number) + 1;
03704       len += strlen(context) + 1;
03705       if (!(qe = ast_calloc(1, len))) {
03706          AST_LIST_UNLOCK(&pcq);
03707          return;
03708       }
03709       strcpy(qe->number, number);
03710       qe->context = qe->number + strlen(number) + 1;
03711       strcpy(qe->context, context);
03712    }
03713    time(&qe->expiration);
03714    qe->expiration += expiration;
03715    if ((prev = AST_LIST_FIRST(&pcq))) {
03716       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03717          prev = AST_LIST_NEXT(prev, list);
03718       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03719    } else
03720       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03721    AST_LIST_UNLOCK(&pcq);
03722 }

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

Definition at line 2405 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02406 {
02407    const struct dundi_result *resa, *resb;
02408    resa = a;
02409    resb = b;
02410    if (resa->weight < resb->weight)
02411       return -1;
02412    if (resa->weight > resb->weight)
02413       return 1;
02414    return 0;
02415 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

00488 {
00489    int tid;
00490    tid = get_trans_id();
00491    if (tid < 1)
00492       return -1;
00493    trans->strans = tid;
00494    trans->dtrans = 0;
00495    trans->iseqno = 0;
00496    trans->oiseqno = 0;
00497    trans->oseqno = 0;
00498    trans->aseqno = 0;
00499    ast_clear_flag(trans, FLAG_FINAL);
00500    return 0;
00501 }

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

Definition at line 2097 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02098 {
02099    char tmp[256];
02100    if (oldkey)
02101       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02102    else
02103       snprintf(tmp, sizeof(tmp), "%s", newkey);
02104    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02105    ast_db_put(secretpath, "secret", tmp);
02106    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02107    ast_db_put(secretpath, "secretexpiry", tmp);
02108 }

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

Definition at line 4638 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, CONFIG_STATUS_FILEINVALID, 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.

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

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

Definition at line 2054 of file pbx_dundi.c.

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

02055 {
02056    struct sockaddr_in sin;
02057    int res;
02058    struct dundi_hdr *h;
02059    char buf[MAX_PACKET_SIZE];
02060    socklen_t len = sizeof(sin);
02061 
02062    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
02063    if (res < 0) {
02064       if (errno != ECONNREFUSED)
02065          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
02066       return 1;
02067    }
02068    if (res < sizeof(struct dundi_hdr)) {
02069       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
02070       return 1;
02071    }
02072    buf[res] = '\0';
02073    h = (struct dundi_hdr *) buf;
02074    if (dundidebug)
02075       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
02076    AST_LIST_LOCK(&peers);
02077    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
02078    AST_LIST_UNLOCK(&peers);
02079    return 1;
02080 }

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

Definition at line 2417 of file pbx_dundi.c.

References rescomp().

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

02418 {
02419    qsort(results, count, sizeof(results[0]), rescomp);
02420 }

static int start_network_thread ( void   )  [static]

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

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

00387 {
00388    if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2"))
00389       return DUNDI_PROTO_IAX;
00390    else if (!strcasecmp(str, "SIP"))
00391       return DUNDI_PROTO_SIP;
00392    else if (!strcasecmp(str, "H323"))
00393       return DUNDI_PROTO_H323;
00394    else
00395       return -1;
00396 }

static char* tech2str ( int  tech  )  [static]

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

00371 {
00372    switch(tech) {
00373    case DUNDI_PROTO_NONE:
00374       return "None";
00375    case DUNDI_PROTO_IAX:
00376       return "IAX2";
00377    case DUNDI_PROTO_SIP:
00378       return "SIP";
00379    case DUNDI_PROTO_H323:
00380       return "H323";
00381    default:
00382       return "Unknown";
00383    }
00384 }

static int unload_module ( void   )  [static]

Definition at line 4779 of file pbx_dundi.c.

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

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

static void unregister_request ( struct dundi_request dr  )  [static]

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

03540 {
03541    AST_LIST_LOCK(&peers);
03542    AST_LIST_REMOVE(&requests, dr, list);
03543    AST_LIST_UNLOCK(&peers);
03544 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1307 of file pbx_dundi.c.

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

01308 {
01309    unsigned char key[16];
01310    struct ast_key *ekey, *skey;
01311    char eid_str[20];
01312    int res;
01313    if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
01314       build_iv(key);
01315       ast_aes_set_encrypt_key(key, &peer->us_ecx);
01316       ast_aes_set_decrypt_key(key, &peer->us_dcx);
01317       ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01318       if (!ekey) {
01319          ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
01320             peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01321          return -1;
01322       }
01323       skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01324       if (!skey) {
01325          ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
01326             peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01327          return -1;
01328       }
01329       if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
01330          ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
01331          return -1;
01332       }
01333       if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
01334          ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
01335          return -1;
01336       }
01337       peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
01338       peer->sentfullkey = 0;
01339       /* Looks good */
01340       time(&peer->keyexpire);
01341       peer->keyexpire += dundi_key_ttl;
01342    }
01343    return 0;
01344 }


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

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

int authdebug = 0 [static]

Definition at line 183 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 180 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2885 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

char country[80] [static]

Definition at line 195 of file pbx_dundi.c.

Referenced by load_indications(), and SendDialTone().

char cursecret[80] [static]

Definition at line 199 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 189 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 191 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 186 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 185 of file pbx_dundi.c.

struct ast_custom_function dundi_query_function [static]

Initial value:

 {
   .name = "DUNDIQUERY",
   .read = dundi_query_read,
}

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

Referenced by dundi_query_read(), and dundifunc_read().

struct ast_datastore_info dundi_result_datastore_info [static]

Initial value:

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

Definition at line 3968 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundi_result_read().

struct ast_custom_function dundi_result_function [static]

Initial value:

 {
   .name = "DUNDIRESULT",
   .read = dundi_result_read,
}

Definition at line 4120 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

unsigned int dundi_result_id [static]

Definition at line 3949 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 203 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4629 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 184 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 182 of file pbx_dundi.c.

char email[80] [static]

Definition at line 196 of file pbx_dundi.c.

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

Definition at line 202 of file pbx_dundi.c.

Referenced by find_peer(), and set_config().

int global_autokilltimeout = 0 [static]

Definition at line 187 of file pbx_dundi.c.

dundi_eid global_eid [static]

Definition at line 188 of file pbx_dundi.c.

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

int global_storehistory = 0 [static]

Definition at line 190 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 175 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 200 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 193 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 177 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 178 of file pbx_dundi.c.

char org[80] [static]

Definition at line 192 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 197 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 179 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 201 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 176 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 198 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 194 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 181 of file pbx_dundi.c.


Generated on Mon Jun 27 16:51:18 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7