Mon Aug 31 12:30:41 2015

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_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_result_datastore
struct  dundi_transaction
struct  mappings
struct  packetlist
struct  pcq
struct  peers
struct  permission
struct  permissionlist
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 = "ac1f6a56484a8820659555499174e588" , .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 build_peer(), 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_peer(), 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 build_peer(), and 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 4196 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 handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 145 of file pbx_dundi.c.

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

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4867 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4867 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3440 of file pbx_dundi.c.

References AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, destroy_trans(), and dundi_request::trans.

Referenced by dundi_lookup_internal().

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

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

Definition at line 1989 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

Definition at line 4183 of file pbx_dundi.c.

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

Referenced by build_peer().

04184 {
04185    struct permission *perm;
04186 
04187    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04188       return;
04189 
04190    strcpy(perm->name, s);
04191    perm->allow = allow;
04192 
04193    AST_LIST_INSERT_TAIL(permlist, perm, list);
04194 }

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

Definition at line 3395 of file pbx_dundi.c.

References dundi_peer::addr, ast_debug, ast_eid_to_str(), AST_LIST_INSERT_HEAD, ast_strlen_zero(), create_transaction(), dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, dundi_peer::maxms, dundi_request::number, dundi_transaction::parent, dundi_request::query_eid, dundi_request::trans, and dundi_transaction::ttl.

Referenced by build_transactions().

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

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

Definition at line 1276 of file pbx_dundi.c.

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

Referenced by create_transaction(), and handle_command_response().

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

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

Definition at line 3561 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

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

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

References dundi_mapping::_weight, ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdup, ast_strdupa, ast_strlen_zero(), dundi_mapping::dcontext, dundi_mapping::dead, dundi_mapping::dest, DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, dundi_mapping::lcontext, LOG_WARNING, map, MAX_OPTS, MAX_WEIGHT, dundi_mapping::options, str2tech(), dundi_mapping::tech, and dundi_mapping::weightstr.

Referenced by set_config().

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

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

Definition at line 4353 of file pbx_dundi.c.

References dundi_peer::addr, append_permission(), ast_calloc, ast_copy_string(), ast_eid_cmp(), ast_eid_to_str(), ast_gethostbyname(), AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_str_to_eid(), ast_true(), dundi_peer::dead, DEFAULT_MAXMS, destroy_permissions(), do_register(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_MODEL_SYMMETRIC, DUNDI_PORT, dundi_peer::dynamic, dundi_peer::eid, hp, dundi_peer::include, dundi_peer::inkey, ast_variable::lineno, LOG_WARNING, dundi_peer::maxms, dundi_peer::model, ast_variable::name, ast_variable::next, dundi_peer::order, dundi_peer::outkey, dundi_peer::pcmodel, dundi_peer::permit, populate_addr(), qualify_peer(), dundi_peer::qualifyid, dundi_peer::registerexpire, dundi_peer::registerid, dundi_peer::us_eid, and ast_variable::value.

Referenced by set_config().

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

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

Definition at line 2079 of file pbx_dundi.c.

References ast_base64encode(), and build_iv().

Referenced by check_password(), and load_password().

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

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

References append_transaction(), ast_clear_flag_nonstd, ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, cache_lookup(), dundi_request::crc32, dundi_request::dcontext, dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, dundi_request::expiration, has_permission(), dundi_request::hmd, dundi_peer::include, dundi_peer::model, dundi_peer::order, pass, dundi_peer::pcmodel, dundi_peer::permit, and dundi_peer::us_eid.

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

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

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

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

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

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

Definition at line 1152 of file pbx_dundi.c.

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

Referenced by cache_lookup().

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

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

Definition at line 881 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 dundi_prop_precache(), and handle_command_response().

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

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

Definition at line 846 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 dundi_prop_precache(), and handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3426 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

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

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

Definition at line 1470 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void check_password ( void   )  [static]

Definition at line 2146 of file pbx_dundi.c.

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

Referenced by network_thread().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3547 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

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

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

Definition at line 2381 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

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

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

Definition at line 2900 of file pbx_dundi.c.

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

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

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

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

Definition at line 1367 of file pbx_dundi.c.

References ast_aes_decrypt().

Referenced by dundi_decrypt().

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

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

Definition at line 1523 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4146 of file pbx_dundi.c.

References ast_free, and dundi_mapping::weightstr.

Referenced by prune_mappings().

04147 {
04148    if (map->weightstr)
04149       ast_free(map->weightstr);
04150    ast_free(map);
04151 }

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

Definition at line 2947 of file pbx_dundi.c.

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

Referenced by ack_trans().

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

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

Definition at line 1978 of file pbx_dundi.c.

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

Referenced by ack_trans(), destroy_trans(), and handle_frame().

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

static void destroy_peer ( struct dundi_peer peer  )  [static]
static void destroy_permissions ( struct permissionlist *  permlist  )  [static]

Definition at line 4127 of file pbx_dundi.c.

References ast_free, and AST_LIST_REMOVE_HEAD.

Referenced by build_peer(), and destroy_peer().

04128 {
04129    struct permission *perm;
04130 
04131    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04132       ast_free(perm);
04133 }

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

Definition at line 2956 of file pbx_dundi.c.

References ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_malloc, AST_SCHED_DEL, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), dundi_transaction::autokillid, dundi_peer::avgms, dundi_request::dcontext, destroy_packets(), DUNDI_TIMING_HISTORY, dundi_peer::eid, errno, FLAG_DEAD, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, dundi_peer::lastms, dundi_transaction::lasttrans, LOG_NOTICE, LOG_WARNING, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::maxms, dundi_request::number, dundi_transaction::packets, dundi_transaction::parent, dundi_request::pfds, dundi_peer::qualtrans, dundi_peer::qualtx, dundi_peer::regtrans, dundi_transaction::start, dundi_transaction::them_eid, dundi_transaction::thread, and dundi_request::trans.

Referenced by abort_request(), destroy_peer(), do_autokill(), do_register(), dundi_lookup_thread(), dundi_precache_thread(), dundi_query_thread(), dundi_rexmit(), handle_frame(), precache_trans(), precache_transactions(), and qualify_peer().

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3278 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_discover(), and dundi_request::trans.

Referenced by dundi_lookup_internal().

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

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

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

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

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

Definition at line 4298 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04299 {
04300    struct dundi_peer *peer = (struct dundi_peer *)data;
04301    peer->qualifyid = -1;
04302    qualify_peer(peer, 0);
04303    return 0;
04304 }

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

Definition at line 4272 of file pbx_dundi.c.

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

Referenced by build_peer().

04273 {
04274    struct dundi_ie_data ied;
04275    struct dundi_peer *peer = (struct dundi_peer *)data;
04276    char eid_str[20];
04277    char eid_str2[20];
04278    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));
04279    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04280    /* Destroy old transaction if there is one */
04281    if (peer->regtrans)
04282       destroy_trans(peer->regtrans, 0);
04283    peer->regtrans = create_transaction(peer);
04284    if (peer->regtrans) {
04285       ast_set_flag(peer->regtrans, FLAG_ISREG);
04286       memset(&ied, 0, sizeof(ied));
04287       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04288       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04289       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04290       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04291 
04292    } else
04293       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));
04294 
04295    return 0;
04296 }

static int do_register_expire ( const void *  data  )  [static]
Note:
Called with the peers list already locked

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

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

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3952 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03953 {
03954    ast_free(drds);
03955 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3957 of file pbx_dundi.c.

References drds_destroy().

03958 {
03959    struct dundi_result_datastore *drds = data;
03960    drds_destroy(drds);
03961 }

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_command_response(), and 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 791 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().

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

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

Definition at line 1069 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04548 {
04549    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04550 }

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, read]

Definition at line 1384 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3166 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::cbypass, dundi_request::dcontext, do_autokill(), DUNDI_COMMAND_DPDISCOVER, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append(), dundi_ie_append_eid(), dundi_ie_append_eid_appropriately(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CACHEBYPASS, DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID_DIRECT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, dundi_request::number, dundi_transaction::parent, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by discover_transactions().

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

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

Definition at line 2420 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_result::dest, dundi_flags2str(), dundi_lookup(), dundi_result::eid_str, dundi_result::expiration, ast_cli_args::fd, sort_results(), dundi_result::tech, ast_cli_entry::usage, and dundi_result::weight.

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

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

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

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

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

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

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

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

Definition at line 1406 of file pbx_dundi.c.

References ast_alloca, ast_debug, ast_log(), ast_set_flag, ast_test_flag, dundi_ie_data::buf, build_iv(), dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dcx, DUNDI_COMMAND_ENCRYPT, dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_int(), dundi_ie_append_raw(), DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_KEYCRC32, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, dundi_transaction::ecx, encrypt_memcpy(), find_peer(), FLAG_SENDFULLKEY, dundi_packet::h, dundi_hdr::ies, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_hdr::oseqno, dundi_ie_data::pos, dundi_peer::sentfullkey, dundi_transaction::them_eid, dundi_peer::txenckey, update_key(), dundi_peer::us_dcx, dundi_peer::us_ecx, dundi_transaction::us_eid, and dundi_peer::us_keycrc32.

Referenced by dundi_send().

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

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04543 {
04544    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04545 }

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

Definition at line 2322 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_db_deltree(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DUNDI_TIMING_HISTORY, ast_cli_args::fd, dundi_peer::lookups, dundi_peer::lookuptimes, and ast_cli_entry::usage.

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

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

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

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

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

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

Definition at line 3144 of file pbx_dundi.c.

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

Referenced by dundi_discover().

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

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

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

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

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

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 3576 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(), dundi_request::cbypass, check_request(), dundi_request::crc32, dundi_request::dcontext, discover_transactions(), dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, dundi_request::trans, and unregister_request().

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

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

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(), dundi_result::dest, dundi_mapping::dest, DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, dundi_result::eid, dundi_result::expiration, dundi_hint_metadata::exten, get_mapping_weight(), dundi_mapping::lcontext, dundi_mapping::options, pbx_substitute_variables_varshead(), dundi_result::tech, dundi_mapping::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

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             if ((newvariable = ast_var_assign("NUMBER", called_number))) {
00598                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00599             }
00600             if ((newvariable = ast_var_assign("EID", dr[anscnt].eid_str))) {
00601                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00602             }
00603             if ((newvariable = ast_var_assign("SECRET", cursecret))) {
00604                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00605             }
00606             if ((newvariable = ast_var_assign("IPADDR", ipaddr))) {
00607                AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00608             }
00609             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00610             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00611                ast_var_delete(newvariable);
00612          } else
00613             dr[anscnt].dest[0] = '\0';
00614          anscnt++;
00615       } else {
00616          /* No answers...  Find the fewest number of digits from the
00617             number for which we have no answer. */
00618          char tmp[AST_MAX_EXTENSION + 1] = "";
00619          for (x = 0; x < (sizeof(tmp) - 1); x++) {
00620             tmp[x] = called_number[x];
00621             if (!tmp[x])
00622                break;
00623             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00624                /* Oops found something we can't match.  If this is longer
00625                   than the running hint, we have to consider it */
00626                if (strlen(tmp) > strlen(hmd->exten)) {
00627                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00628                }
00629                break;
00630             }
00631          }
00632       }
00633    }
00634    return anscnt;
00635 }

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

Definition at line 639 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), dundi_query_state::directs, DUNDI_CAUSE_DUPLICATE, DUNDI_COMMAND_DPRESPONSE, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_cause(), dundi_ie_append_hint(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_query_state::eids, dundi_result::expiration, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by dundi_answer_query().

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

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04608 {
04609    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04610 }

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

Pre-cache to push upstream peers.

Definition at line 3821 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

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

static void dundi_precache_full ( void   )  [static]

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

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

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

Definition at line 3749 of file pbx_dundi.c.

References ast_alloca, ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dundi_request::dcontext, dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, precache_transactions(), reschedule_precache(), and dundi_request::trans.

Referenced by dundi_precache(), and dundi_precache_thread().

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

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

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

Referenced by dundi_prop_precache().

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

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

Definition at line 922 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, cache_save(), cache_save_hint(), dundi_query_state::called_context, dundi_ies::called_context, dundi_query_state::called_number, dundi_ies::called_number, dundi_ies::cbypass, dundi_answer::data, dundi_mapping::dcontext, dundi_request::dcontext, dundi_result::dest, dundi_query_state::directs, dundi_request::dr, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_PRECACHERP, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_precache_thread(), dundi_send(), dundi_answer::eid, dundi_result::eid, dundi_ies::eid_direct, dundi_result::eid_str, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_result::expiration, dundi_ies::expiration, dundi_request::expiration, dundi_answer::flags, dundi_result::flags, dundi_hint_metadata::flags, dundi_query_state::fluffy, dundi_ies::hint, dundi_request::hmd, dundi_mapping::list, LOG_NOTICE, LOG_WARNING, dundi_query_state::maps, dundi_request::maxcount, dundi_mapping::next, dundi_query_state::nocache, dundi_request::number, dundi_query_state::nummaps, dundi_transaction::parent, dundi_request::pfds, dundi_answer::protocol, dundi_request::respcount, dundi_result::tech, tech2str(), dundi_result::techint, dundi_transaction::them_eid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, dundi_query_state::ttl, dundi_answer::weight, and dundi_result::weight.

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3256 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, do_autokill(), DUNDI_COMMAND_EIDQUERY, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append_eid(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_EID, DUNDI_IE_REQEID, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, dundi_transaction::parent, dundi_request::query_eid, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by query_transactions().

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

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

Retrieve information on a specific EID.

Definition at line 3874 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

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

static int dundi_query_eid_internal ( struct dundi_entity_info dei,
const char *  dcontext,
dundi_eid eid,
struct dundi_hint_metadata hmd,
int  ttl,
int  blockempty,
dundi_eid avoid[] 
) [static]

Definition at line 3827 of file pbx_dundi.c.

References ast_copy_string(), AST_LIST_EMPTY, ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), build_transactions(), dundi_request::dcontext, dundi_request::dei, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, dundi_request::hmd, optimize_transactions(), dundi_request::pfds, dundi_request::query_eid, query_transactions(), dundi_request::respcount, dundi_request::root_eid, and dundi_request::trans.

Referenced by dundi_query_eid(), and dundi_query_thread().

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

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

Definition at line 3968 of file pbx_dundi.c.

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

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

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

Definition at line 736 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, dundi_entity_info::country, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, dundi_entity_info::email, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, dundi_query_state::reqeid, dundi_entity_info::stateprov, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

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

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

Definition at line 444 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_hdr::cmdresp, dundi_hdr::dtrans, DUNDI_COMMAND_INVALID, dundi_xmit(), dundi_hdr::iseqno, dundi_hdr::oseqno, 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 4032 of file pbx_dundi.c.

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

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

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

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

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

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

Definition at line 3062 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, ast_eid_to_str(), ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_sched_add(), ast_set_flag, ast_test_flag, dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_ACK, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_FINAL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_DEFAULT_RETRANS, dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, dundi_packet::h, dundi_hdr::ies, dundi_transaction::iseqno, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::packets, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, dundi_transaction::retranstimer, dundi_transaction::strans, dundi_hdr::strans, and dundi_transaction::them_eid.

Referenced by cancel_request(), do_register(), dundi_ack(), dundi_answer_entity(), dundi_answer_query(), dundi_discover(), dundi_lookup_thread(), dundi_precache_thread(), dundi_prop_precache(), dundi_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().

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

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

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

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

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

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

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

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

Definition at line 2814 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_mapping::dcontext, dundi_mapping::dest, dundi_flags2str(), ast_cli_args::fd, FORMAT, FORMAT2, get_mapping_weight(), dundi_mapping::lcontext, map, dundi_mapping::options, dundi_mapping::tech, tech2str(), and ast_cli_entry::usage.

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

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

Definition at line 2561 of file pbx_dundi.c.

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

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

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

Definition at line 2636 of file pbx_dundi.c.

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

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

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

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

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

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

Definition at line 2782 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

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

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

Definition at line 3890 of file pbx_dundi.c.

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

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

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

Definition at line 1351 of file pbx_dundi.c.

References ast_aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 504 of file pbx_dundi.c.

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

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

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, read]

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

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 dundi_mapping::_weight, MAX_WEIGHT, pbx_substitute_variables_helper(), and dundi_mapping::weightstr.

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

References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, apply_peer(), dundi_transaction::aseqno, ast_alloca, ast_calloc, ast_clear_flag, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_set_flag, ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verb, cache_save(), cache_save_hint(), dundi_ies::called_context, dundi_ies::called_number, dundi_ies::cause, check_key(), dundi_hdr::cmdresp, dundi_entity_info::country, dundi_hint::data, dundi_answer::data, dundi_request::dcontext, dundi_transaction::dcx, deep_copy_peer(), dundi_request::dei, dundi_result::dest, do_register_expire(), dundi_request::dr, dundi_ack(), dundi_answer_entity(), dundi_answer_query(), DUNDI_CAUSE_GENERAL, DUNDI_CAUSE_NOAUTH, DUNDI_COMMAND_CANCEL, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_ENCREJ, DUNDI_COMMAND_ENCRYPT, DUNDI_COMMAND_INVALID, DUNDI_COMMAND_NULL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_COMMAND_UNKNOWN, dundi_decrypt(), dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_byte(), dundi_ie_append_cause(), dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_raw(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_EXPIRATION, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, DUNDI_IE_UNKNOWN, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_showframe(), dundi_peer::dynamic, dundi_transaction::ecx, dundi_answer::eid, dundi_result::eid, dundi_peer::eid, dundi_result::eid_str, dundi_ies::eidcount, dundi_ies::eids, dundi_entity_info::email, dundi_ies::encblock, dundi_encblock::encdata, dundi_ies::enclen, dundi_ies::encsharedkey, dundi_ies::encsig, dundi_request::expiration, dundi_result::expiration, dundi_ies::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, FLAG_SENDFULLKEY, dundi_answer::flags, dundi_result::flags, has_permission(), dundi_ies::hint, dundi_request::hmd, dundi_hdr::ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, dundi_entity_info::ipaddr, dundi_transaction::iseqno, dundi_encblock::iv, dundi_ies::keycrc32, dundi_transaction::lasttrans, dundi_entity_info::locality, LOG_NOTICE, LOG_WARNING, MAX_PACKET_SIZE, dundi_request::maxcount, dundi_peer::model, dundi_request::number, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_entity_info::phone, dundi_ie_data::pos, dundi_answer::protocol, dundi_ies::q_country, dundi_ies::q_dept, dundi_ies::q_email, dundi_ies::q_ipaddr, dundi_ies::q_locality, dundi_ies::q_org, dundi_ies::q_phone, dundi_ies::q_stateprov, qualify_peer(), dundi_request::query_eid, dundi_peer::registerexpire, reset_transaction(), dundi_request::respcount, dundi_peer::sentfullkey, dundi_entity_info::stateprov, dundi_result::tech, tech2str(), dundi_result::techint, dundi_peer::them_dcx, dundi_peer::them_ecx, dundi_transaction::them_eid, dundi_peer::txenckey, dundi_peer::us_eid, dundi_transaction::us_eid, dundi_answer::weight, and dundi_result::weight.

Referenced by handle_frame().

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

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

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

Referenced by socket_read().

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

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, 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 4809 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, dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, sched_context_create(), set_config(), and start_network_thread().

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

static void load_password ( void   )  [static]

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

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

static void mark_mappings ( void   )  [static]

Definition at line 4116 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

04117 {
04118    struct dundi_mapping *map;
04119 
04120    AST_LIST_LOCK(&peers);
04121    AST_LIST_TRAVERSE(&mappings, map, list) {
04122       map->dead = 1;
04123    }
04124    AST_LIST_UNLOCK(&peers);
04125 }

static void mark_peers ( void   )  [static]

Definition at line 4106 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

04107 {
04108    struct dundi_peer *peer;
04109    AST_LIST_LOCK(&peers);
04110    AST_LIST_TRAVERSE(&peers, peer, list) {
04111       peer->dead = 1;
04112    }
04113    AST_LIST_UNLOCK(&peers);
04114 }

static char* model2str ( int  model  )  [static]

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

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

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

Definition at line 2163 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

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

Definition at line 3337 of file pbx_dundi.c.

References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), dundi_peer::include, dundi_peer::lastms, dundi_peer::order, dundi_transaction::them_eid, dundi_request::trans, and dundi_transaction::us_eid.

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

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

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

Definition at line 4329 of file pbx_dundi.c.

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

Referenced by build_peer().

04330 {
04331    char data[256];
04332    char *c;
04333    int port, expire;
04334    char eid_str[20];
04335    ast_eid_to_str(eid_str, sizeof(eid_str), eid);
04336    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04337       c = strchr(data, ':');
04338       if (c) {
04339          *c = '\0';
04340          c++;
04341          if (sscanf(c, "%5d:%30d", &port, &expire) == 2) {
04342             /* Got it! */
04343             inet_aton(data, &peer->addr.sin_addr);
04344             peer->addr.sin_family = AF_INET;
04345             peer->addr.sin_port = htons(port);
04346             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04347          }
04348       }
04349    }
04350 }

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

Definition at line 3190 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, destroy_trans(), do_autokill(), 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, dundi_result::expiration, dundi_hint_metadata::exten, dundi_hint_metadata::flags, LOG_WARNING, dundi_request::number, dundi_transaction::parent, dundi_transaction::them_eid, dundi_transaction::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by precache_transactions().

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

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

Definition at line 3289 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(), FLAG_DEAD, LOG_WARNING, precache_trans(), dundi_transaction::thread, and dundi_request::trans.

Referenced by dundi_precache_internal().

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

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

Definition at line 2190 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

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

Definition at line 2224 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, and dundi_precache_queue::number.

Referenced by start_network_thread().

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

static void prune_mappings ( void   )  [static]

Definition at line 4168 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_mapping::dead, destroy_map(), and map.

Referenced by set_config(), and unload_module().

04169 {
04170    struct dundi_mapping *map;
04171 
04172    AST_LIST_LOCK(&peers);
04173    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
04174       if (map->dead) {
04175          AST_LIST_REMOVE_CURRENT(list);
04176          destroy_map(map);
04177       }
04178    }
04179    AST_LIST_TRAVERSE_SAFE_END;
04180    AST_LIST_UNLOCK(&peers);
04181 }

static void prune_peers ( void   )  [static]

Definition at line 4153 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, and destroy_peer().

Referenced by set_config(), and unload_module().

04154 {
04155    struct dundi_peer *peer;
04156 
04157    AST_LIST_LOCK(&peers);
04158    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
04159       if (peer->dead) {
04160          AST_LIST_REMOVE_CURRENT(list);
04161          destroy_peer(peer);
04162       }
04163    }
04164    AST_LIST_TRAVERSE_SAFE_END;
04165    AST_LIST_UNLOCK(&peers);
04166 }

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

Definition at line 4306 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, and dundi_peer::qualtx.

Referenced by build_peer(), do_qualify(), and handle_command_response().

04307 {
04308    int when;
04309    AST_SCHED_DEL(sched, peer->qualifyid);
04310    if (peer->qualtrans)
04311       destroy_trans(peer->qualtrans, 0);
04312    peer->qualtrans = NULL;
04313    if (peer->maxms > 0) {
04314       when = 60000;
04315       if (peer->lastms < 0)
04316          when = 10000;
04317       if (schedonly)
04318          when = 5000;
04319       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04320       if (!schedonly)
04321          peer->qualtrans = create_transaction(peer);
04322       if (peer->qualtrans) {
04323          peer->qualtx = ast_tvnow();
04324          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04325          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04326       }
04327    }
04328 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3324 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_query(), and dundi_request::trans.

Referenced by dundi_query_eid_internal().

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

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

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

Referenced by dundi_lookup_internal().

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

static int reload ( void   )  [static]

Definition at line 4799 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04800 {
04801    struct sockaddr_in sin;
04802 
04803    if (set_config("dundi.conf", &sin, 1))
04804       return AST_MODULE_LOAD_FAILURE;
04805 
04806    return AST_MODULE_LOAD_SUCCESS;
04807 }

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

Definition at line 3689 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(), and dundi_precache_queue::number.

Referenced by dundi_precache_full(), and dundi_precache_internal().

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

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

Definition at line 2403 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

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

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.

Referenced by handle_command_response().

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

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

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

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

Definition at line 4621 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_STATUS_FILEINVALID, DEFAULT_MAXMS, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), find_peer(), hp, ast_variable::lineno, load_password(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mark_mappings(), mark_peers(), MAXHOSTNAMELEN, ast_variable::name, ast_variable::next, prune_mappings(), prune_peers(), and ast_variable::value.

Referenced by load_module(), and reload().

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

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

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

Referenced by network_thread().

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

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

Definition at line 2415 of file pbx_dundi.c.

References rescomp().

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

02416 {
02417    qsort(results, count, sizeof(results[0]), rescomp);
02418 }

static int start_network_thread ( void   )  [static]
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 4762 of file pbx_dundi.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_PTHREADT_NULL, ast_unregister_switch(), io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), and sched_context_destroy().

04763 {
04764    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid, previous_clearcachethreadid = clearcachethreadid;
04765 
04766    ast_cli_unregister_multiple(cli_dundi, ARRAY_LEN(cli_dundi));
04767    ast_unregister_switch(&dundi_switch);
04768    ast_custom_function_unregister(&dundi_function);
04769    ast_custom_function_unregister(&dundi_query_function);
04770    ast_custom_function_unregister(&dundi_result_function);
04771 
04772    /* Stop all currently running threads */
04773    dundi_shutdown = 1;
04774    if (previous_netthreadid != AST_PTHREADT_NULL) {
04775       pthread_kill(previous_netthreadid, SIGURG);
04776       pthread_join(previous_netthreadid, NULL);
04777    }
04778    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04779       pthread_kill(previous_precachethreadid, SIGURG);
04780       pthread_join(previous_precachethreadid, NULL);
04781    }
04782    if (previous_clearcachethreadid != AST_PTHREADT_NULL) {
04783       pthread_cancel(previous_clearcachethreadid);
04784       pthread_join(previous_clearcachethreadid, NULL);
04785    }
04786 
04787    close(netsocket);
04788    io_context_destroy(io);
04789    sched_context_destroy(sched);
04790 
04791    mark_mappings();
04792    prune_mappings();
04793    mark_peers();
04794    prune_peers();
04795 
04796    return 0;
04797 }

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3540 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

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

static int update_key ( struct dundi_peer peer  )  [static]

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

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


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

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

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

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.

Initial value:
 {
   .name = "DUNDIQUERY",
   .read = dundi_query_read,
}

Definition at line 4027 of file pbx_dundi.c.

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

Definition at line 3888 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundifunc_read().

Initial value:
 {
   .type = "DUNDIQUERY",
   .destroy = drds_destroy_cb,
}

Definition at line 3963 of file pbx_dundi.c.

Initial value:
 {
   .name = "DUNDIRESULT",
   .read = dundi_result_read,
}

Definition at line 4101 of file pbx_dundi.c.

unsigned int dundi_result_id [static]

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

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.

int global_autokilltimeout = 0 [static]

Definition at line 188 of file pbx_dundi.c.

Definition at line 189 of file pbx_dundi.c.

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 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1