Sat Mar 10 01:55:36 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 168 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 151 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

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

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 173 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 156 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 4217 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 147 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

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

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

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3884 of file pbx_dundi.c.

03884      {
03885    OPT_BYPASS_CACHE = (1 << 0),
03886 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4886 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4886 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3441 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

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

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

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

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

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

Definition at line 4204 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

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

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

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

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

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

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

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

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

Definition at line 3562 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

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

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

Definition at line 522 of file pbx_dundi.c.

References ast_random().

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

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

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

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

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

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

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

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

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

Definition at line 2083 of file pbx_dundi.c.

References ast_base64encode(), and build_iv().

Referenced by check_password(), and load_password().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void cancel_request ( struct dundi_request dr  )  [static]

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

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

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

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

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

static void check_password ( void   )  [static]

Definition at line 2150 of file pbx_dundi.c.

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

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

static int check_request ( struct dundi_request dr  )  [static]

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

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

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

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

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

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

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

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

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

Definition at line 1363 of file pbx_dundi.c.

References ast_aes_decrypt().

Referenced by dundi_decrypt().

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

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

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

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4167 of file pbx_dundi.c.

References ast_free, and map.

Referenced by prune_mappings().

04168 {
04169    if (map->weightstr)
04170       ast_free(map->weightstr);
04171    ast_free(map);
04172 }

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

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

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

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

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

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

static void destroy_peer ( struct dundi_peer peer  )  [static]

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

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

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

Definition at line 4148 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, and permission::list.

Referenced by build_peer(), and destroy_peer().

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

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

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

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3281 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

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

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

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

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

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

Definition at line 4319 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

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

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

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

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

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

Note:
Called with the peers list already locked

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

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

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3959 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03960 {
03961    ast_free(drds);
03962 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3964 of file pbx_dundi.c.

References drds_destroy().

03965 {
03966    struct dundi_result_datastore *drds = data;
03967    drds_destroy(drds);
03968 }

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

Definition at line 440 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

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

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

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

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

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

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

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

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04567 {
04568    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04569 }

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

Definition at line 347 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

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

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

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

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 353 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04562 {
04563    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04564 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04627 {
04628    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04629 }

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

Pre-cache to push upstream peers.

Definition at line 3823 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

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

static void dundi_precache_full ( void   )  [static]

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

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

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

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

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

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

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

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

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

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

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

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

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

Retrieve information on a specific EID.

Definition at line 3876 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

02735 {
02736 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02737 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02738    struct dundi_transaction *trans;
02739    switch (cmd) {
02740    case CLI_INIT:
02741       e->command = "dundi show trans";
02742       e->usage =
02743          "Usage: dundi show trans\n"
02744          "       Lists all known DUNDi transactions.\n";
02745       return NULL;
02746    case CLI_GENERATE:
02747       return NULL;
02748    }
02749    if (a->argc != 3)
02750       return CLI_SHOWUSAGE;
02751    AST_LIST_LOCK(&peers);
02752    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02753    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02754       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),
02755          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02756    }
02757    AST_LIST_UNLOCK(&peers);
02758    return CLI_SUCCESS;
02759 #undef FORMAT
02760 #undef FORMAT2
02761 }

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

Definition at line 2298 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_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.

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

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

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

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

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

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

Definition at line 1347 of file pbx_dundi.c.

References ast_aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 504 of file pbx_dundi.c.

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

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

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

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

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

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 548 of file pbx_dundi.c.

References map, MAX_WEIGHT, and pbx_substitute_variables_helper().

Referenced by dundi_lookup_local(), and dundi_show_mappings().

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

static int get_trans_id ( void   )  [static]

Definition at line 469 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

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

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

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

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

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

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

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

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

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

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

static int load_module ( void   )  [static]

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

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

static void load_password ( void   )  [static]

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

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

static void mark_mappings ( void   )  [static]

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

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

static void mark_peers ( void   )  [static]

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

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

static char* model2str ( int  model  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void prune_mappings ( void   )  [static]

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

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

static void prune_peers ( void   )  [static]

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

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

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

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

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

static int query_transactions ( struct dundi_request dr  )  [static]

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

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

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

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

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

static int reload ( void   )  [static]

Definition at line 4818 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

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

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

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

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

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

Definition at line 2406 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

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

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

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

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

Definition at line 2098 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

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

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

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

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

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

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

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

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

Definition at line 2418 of file pbx_dundi.c.

References rescomp().

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

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

static int start_network_thread ( void   )  [static]

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

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

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

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

static int unload_module ( void   )  [static]

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

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

static void unregister_request ( struct dundi_request dr  )  [static]

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

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

static int update_key ( struct dundi_peer peer  )  [static]

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

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


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

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

int authdebug = 0 [static]

Definition at line 184 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 181 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2887 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

char country[80] [static]

Definition at line 196 of file pbx_dundi.c.

Referenced by load_indications(), and SendDialTone().

char cursecret[80] [static]

Definition at line 200 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 190 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 192 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 187 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 186 of file pbx_dundi.c.

struct ast_custom_function dundi_query_function [static]

Initial value:

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

Definition at line 4043 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 3890 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 3970 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 4122 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

unsigned int dundi_result_id [static]

Definition at line 3951 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 204 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4631 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 185 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 183 of file pbx_dundi.c.

char email[80] [static]

Definition at line 197 of file pbx_dundi.c.

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

Definition at line 203 of file pbx_dundi.c.

Referenced by find_peer(), and set_config().

int global_autokilltimeout = 0 [static]

Definition at line 188 of file pbx_dundi.c.

dundi_eid global_eid [static]

Definition at line 189 of file pbx_dundi.c.

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

int global_storehistory = 0 [static]

Definition at line 191 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 176 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 201 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 194 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 178 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 179 of file pbx_dundi.c.

char org[80] [static]

Definition at line 193 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 198 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 180 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 202 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 177 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 199 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 195 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 182 of file pbx_dundi.c.


Generated on Sat Mar 10 01:55:36 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7