Fri Nov 12 12:06:35 2010

Asterisk developer's documentation


pbx_dundi.c File Reference

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

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

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 %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64
#define MAX_WEIGHT   59999

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void abort_request (struct dundi_request *dr)
static int ack_trans (struct dundi_transaction *trans, int iseqno)
static void append_permission (struct permissionlist *permlist, const char *s, int allow)
static int append_transaction (struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
static void apply_peer (struct dundi_transaction *trans, struct dundi_peer *p)
static unsigned long avoid_crc32 (dundi_eid *avoid[])
static void build_iv (unsigned char *iv)
static void build_mapping (const char *name, const char *value)
static void build_peer (dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
static void build_secret (char *secret, int seclen)
static void build_transactions (struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
static int cache_lookup (struct dundi_request *req, dundi_eid *peer_eid, uint32_t crc32, int *lowexpiration)
static int cache_lookup_internal (time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
static int cache_save (dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
static int cache_save_hint (dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
static void cancel_request (struct dundi_request *dr)
static int check_key (struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, uint32_t keycrc32)
static void check_password (void)
static int check_request (struct dundi_request *dr)
static char * complete_peer_helper (const char *line, const char *word, int pos, int state, int rpos)
static struct dundi_transactioncreate_transaction (struct dundi_peer *p)
static int decrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_decrypt_key *dcx)
static void deep_copy_peer (struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
static void destroy_map (struct dundi_mapping *map)
static void destroy_packet (struct dundi_packet *pack, int needfree)
static void destroy_packets (struct packetlist *p)
static void destroy_peer (struct dundi_peer *peer)
static void destroy_permissions (struct permissionlist *permlist)
static void destroy_trans (struct dundi_transaction *trans, int fromtimeout)
static int discover_transactions (struct dundi_request *dr)
static int do_autokill (const void *data)
static int do_qualify (const void *data)
static int do_register (const void *data)
static int do_register_expire (const void *data)
static void drds_destroy (struct dundi_result_datastore *drds)
static void drds_destroy_cb (void *data)
static int dundi_ack (struct dundi_transaction *trans, int final)
static int dundi_answer_entity (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_answer_query (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static void dundi_debug_output (const char *data)
static struct dundi_hdrdundi_decrypt (struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
static int dundi_discover (struct dundi_transaction *trans)
static char * dundi_do_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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct dundi_peerany_peer
 Wildcard peer.
static struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 0
static pthread_t clearcachethreadid = AST_PTHREADT_NULL
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
static int default_expiration = 60
static char dept [80]
static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME
static struct ast_custom_function dundi_function
static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE
static struct ast_custom_function dundi_query_function
static struct ast_app_option dundi_query_opts [128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, }
static struct ast_datastore_info dundi_result_datastore_info
static struct ast_custom_function dundi_result_function
unsigned int dundi_result_id
static int dundi_shutdown = 0
static struct ast_switch dundi_switch
static int dundi_ttl = DUNDI_DEFAULT_TTL
static int dundidebug = 0
static char email [80]
static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }
static int global_autokilltimeout = 0
static dundi_eid global_eid
static int global_storehistory = 0
static struct io_contextio
static char ipaddr [80]
static char locality [80]
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char org [80]
static char phone [80]
static pthread_t precachethreadid = AST_PTHREADT_NULL
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static char stateprov [80]
static unsigned int tos = 0

Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 167 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 150 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 151 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 152 of file pbx_dundi.c.

Referenced by build_peer(), and model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 172 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10

Keep times of last 10 lookups

Definition at line 155 of file pbx_dundi.c.

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

#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
#define FORMAT   "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
#define FORMAT   "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
#define MAX_OPTS   128

Definition at line 4214 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 146 of file pbx_dundi.c.

Referenced by handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 144 of file pbx_dundi.c.

#define MAX_WEIGHT   59999

Definition at line 148 of file pbx_dundi.c.

Referenced by build_mapping(), and get_mapping_weight().


Enumeration Type Documentation

anonymous enum
Enumerator:
FLAG_ISREG 

Transaction is register request

FLAG_DEAD 

Transaction is dead

FLAG_FINAL 

Transaction has final message sent

FLAG_ISQUAL 

Transaction is a qualification

FLAG_ENCRYPT 

Transaction is encrypted wiht ECX/DCX

FLAG_SENDFULLKEY 

Send full key on transaction

FLAG_STOREHIST 

Record historic performance

Definition at line 157 of file pbx_dundi.c.

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

anonymous enum
Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3881 of file pbx_dundi.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4880 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4880 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

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

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

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

Definition at line 1992 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

Definition at line 4201 of file pbx_dundi.c.

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

Referenced by build_peer().

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

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

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

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

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

Definition at line 1271 of file pbx_dundi.c.

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

Referenced by create_transaction(), and handle_command_response().

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

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

Definition at line 3559 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

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

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

Definition at line 521 of file pbx_dundi.c.

References ast_random().

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

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

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

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

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

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

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

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

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

Definition at line 2082 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

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

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

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

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

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

Definition at line 1219 of file pbx_dundi.c.

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

Referenced by build_transactions().

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

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

Definition at line 1147 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_db_del(), ast_db_get(), ast_debug, ast_eid_to_str(), AST_FLAGS_ALL, ast_get_time_t(), dundi_result::dest, dundi_request::dr, dundi_flags2str(), DUNDI_HINT_DONT_ASK, dundi_str_short_to_eid(), 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().

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

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

Definition at line 876 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

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

Definition at line 841 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

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

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

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_decrypt_key, ast_aes_encrypt_key, ast_check_signature_bin, ast_debug, ast_decrypt_bin, ast_eid_to_str(), ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_peer::eid, dundi_peer::inkey, LOG_NOTICE, dundi_peer::outkey, dundi_peer::rxenckey, dundi_peer::them_dcx, dundi_peer::them_ecx, and dundi_peer::them_keycrc32.

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_decrypt_key(dst, &peer->them_dcx);
01519    ast_aes_encrypt_key(dst, &peer->them_ecx);
01520    return 1;
01521 }

static void check_password ( void   )  [static]

Definition at line 2149 of file pbx_dundi.c.

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

Referenced by network_thread().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3545 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

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

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

Definition at line 2383 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

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

static struct dundi_transaction * create_transaction ( struct dundi_peer p  )  [static, 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 1362 of file pbx_dundi.c.

References ast_aes_decrypt.

Referenced by dundi_decrypt().

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

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

Definition at line 1523 of file pbx_dundi.c.

References permission::allow, ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, dundi_peer::include, permission::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 4164 of file pbx_dundi.c.

References ast_free, and dundi_mapping::weightstr.

Referenced by prune_mappings().

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

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

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

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

Definition at line 4145 of file pbx_dundi.c.

References ast_free, and AST_LIST_REMOVE_HEAD.

Referenced by build_peer(), and destroy_peer().

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

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

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

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

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

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

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

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

Definition at line 1296 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3956 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03957 {
03958    ast_free(drds);
03959 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3961 of file pbx_dundi.c.

References drds_destroy().

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

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

Definition at line 439 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_command_response(), and handle_frame().

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

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

Definition at line 786 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 1064 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 4561 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

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

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

Definition at line 346 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

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

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

Definition at line 1379 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, 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.

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

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

Definition at line 2476 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache(), ast_cli_args::fd, and ast_cli_entry::usage.

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

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

Definition at line 2513 of file pbx_dundi.c.

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

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

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

Definition at line 1403 of file pbx_dundi.c.

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

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

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

Definition at line 352 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04557 {
04558    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04559 }

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

Definition at line 2324 of file pbx_dundi.c.

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

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

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

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

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

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

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

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 3574 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, ast_channel::name, 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().

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

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

Definition at line 561 of file pbx_dundi.c.

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

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

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

Definition at line 634 of file pbx_dundi.c.

References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), dundi_query_state::directs, 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().

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

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

Definition at line 4621 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04622 {
04623    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04624 }

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

Pre-cache to push upstream peers.

Definition at line 3820 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

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

static void dundi_precache_full ( void   )  [static]

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

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

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

Definition at line 3747 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), 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().

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

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

Definition at line 698 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache().

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

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

Definition at line 917 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_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, s, 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().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

References dundi_query_eid_internal().

Referenced by dundi_do_query().

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

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

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

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

Definition at line 3972 of file pbx_dundi.c.

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

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

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

Definition at line 731 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, 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().

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

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

Definition at line 443 of file pbx_dundi.c.

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

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

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

Definition at line 4045 of file pbx_dundi.c.

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

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

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

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

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

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

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

References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_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.

02564 {
02565    struct dundi_peer *peer;
02566    struct permission *p;
02567    char *order;
02568    char eid_str[20];
02569    int x, cnt;
02570    switch (cmd) {
02571    case CLI_INIT:
02572       e->command = "dundi show peer";
02573       e->usage =
02574          "Usage: dundi show peer [peer]\n"
02575          "       Provide a detailed description of a specifid DUNDi peer.\n";
02576       return NULL;
02577    case CLI_GENERATE:
02578       return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
02579    }
02580    if (a->argc != 4)
02581       return CLI_SHOWUSAGE;
02582    AST_LIST_LOCK(&peers);
02583    AST_LIST_TRAVERSE(&peers, peer, list) {
02584       if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
02585          break;
02586    }
02587    if (peer) {
02588       switch(peer->order) {
02589       case 0:
02590          order = "Primary";
02591          break;
02592       case 1:
02593          order = "Secondary";
02594          break;
02595       case 2:
02596          order = "Tertiary";
02597          break;
02598       case 3:
02599          order = "Quartiary";
02600          break;
02601       default:
02602          order = "Unknown";
02603       }
02604       ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02605       ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));
02606       ast_cli(a->fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02607       ast_cli(a->fd, "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     %-10.10s %-8.8s %-15.15s\n"
02639 #define FORMAT "%-20.20s %-15.15s %s %-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", "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)", 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)", 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, s, 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 2297 of file pbx_dundi.c.

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

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

03890 {
03891    int results;
03892    int x;
03893    struct ast_module_user *u;
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    u = ast_module_user_add(chan);
03911 
03912    parse = ast_strdupa(num);
03913 
03914    AST_STANDARD_APP_ARGS(args, parse);
03915 
03916    if (!ast_strlen_zero(args.options)) {
03917       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03918    }
03919    if (ast_strlen_zero(args.context)) {
03920       args.context = "e164";
03921    }
03922 
03923    results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
03924    if (results > 0) {
03925       sort_results(dr, results);
03926       for (x = 0; x < results; x++) {
03927          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03928             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03929             break;
03930          }
03931       }
03932    }
03933 
03934    ast_module_user_remove(u);
03935 
03936    return 0;
03937 }

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

Definition at line 1346 of file pbx_dundi.c.

References ast_aes_encrypt.

Referenced by dundi_encrypt().

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

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

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

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

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

Definition at line 401 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 547 of file pbx_dundi.c.

References dundi_mapping::_weight, buf, MAX_WEIGHT, pbx_substitute_variables_helper(), and dundi_mapping::weightstr.

Referenced by dundi_lookup_local(), and dundi_show_mappings().

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

static int get_trans_id ( void   )  [static]

Definition at line 468 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1553 of file pbx_dundi.c.

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

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

Definition at line 2013 of file pbx_dundi.c.

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

Referenced by socket_read().

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

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

Definition at line 357 of file pbx_dundi.c.

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

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

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

static int load_module ( void   )  [static]

Definition at line 4823 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_FAILURE, 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().

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

static void load_password ( void   )  [static]

Definition at line 2110 of file pbx_dundi.c.

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

Referenced by set_config().

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

static void mark_mappings ( void   )  [static]

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

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

static void mark_peers ( void   )  [static]

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

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

static char* model2str ( int  model  )  [static]

Definition at line 2369 of file pbx_dundi.c.

References DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, and DUNDI_MODEL_SYMMETRIC.

Referenced by dundi_show_peer(), and dundi_show_peers().

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

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

Definition at line 2166 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

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

Definition at line 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::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 (has_permission(&peer->include, dr->dcontext) &&
03360              ast_eid_cmp(&peer->eid, &trans->them_eid) &&
03361             (peer->order <= order)) {
03362             /* For each other transaction, make sure we don't
03363                ask this EID about the others if they're not
03364                already in the list */
03365             if (!ast_eid_cmp(&tmp, &peer->eid))
03366                x = -1;
03367             else {
03368                for (x=0;x<trans->eidcount;x++) {
03369                   if (!ast_eid_cmp(&trans->eids[x], &peer->eid))
03370                      break;
03371                }
03372             }
03373             if (x == trans->eidcount) {
03374                /* Nope not in the list, if needed, add us at the end since we're the source */
03375                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03376                   trans->eids[trans->eidcount++] = peer->eid;
03377                   /* Need to insert the real root (or us) at the bottom now as
03378                      a requirement now.  */
03379                   needpush = 1;
03380                }
03381             }
03382          }
03383       }
03384       /* If necessary, push the true root back on the end */
03385       if (needpush)
03386          trans->eids[trans->eidcount++] = tmp;
03387    }
03388    AST_LIST_UNLOCK(&peers);
03389 
03390    return 0;
03391 }

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

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

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

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

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

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

Definition at line 2226 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

static void prune_mappings ( void   )  [static]

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

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

static void prune_peers ( void   )  [static]

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

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

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

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

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

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

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

static int reload ( void   )  [static]

Definition at line 4813 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

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

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

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

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

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

Definition at line 2405 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

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

static int reset_transaction ( struct dundi_transaction trans  )  [static]

Definition at line 487 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 2097 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

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

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

Definition at line 4635 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(), ast_variable::name, ast_variable::next, prune_mappings(), prune_peers(), and ast_variable::value.

Referenced by load_module(), and reload().

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

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

Definition at line 2054 of file pbx_dundi.c.

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

Referenced by network_thread().

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

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

Definition at line 2417 of file pbx_dundi.c.

References rescomp().

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

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

static int start_network_thread ( void   )  [static]
static int str2tech ( char *  str  )  [static]

Definition at line 386 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

Definition at line 370 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, DUNDI_PROTO_NONE, and DUNDI_PROTO_SIP.

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

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

static int unload_module ( void   )  [static]

Definition at line 4776 of file pbx_dundi.c.

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

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

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3538 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

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

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1307 of file pbx_dundi.c.

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

Referenced by dundi_encrypt().

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


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Distributed Universal Number Discovery (DUNDi)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4880 of file pbx_dundi.c.

struct dundi_peer* any_peer [static]

Wildcard peer.

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

Definition at line 342 of file pbx_dundi.c.

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

Definition at line 4880 of file pbx_dundi.c.

int authdebug = 0 [static]

Definition at line 183 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 180 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2884 of file pbx_dundi.c.

char country[80] [static]

Definition at line 195 of file pbx_dundi.c.

Referenced by load_indications(), and SendDialTone().

char cursecret[80] [static]

Definition at line 199 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 189 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 191 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 186 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 185 of file pbx_dundi.c.

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

Definition at line 4040 of file pbx_dundi.c.

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

Definition at line 3887 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundifunc_read().

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

Definition at line 3967 of file pbx_dundi.c.

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

Definition at line 4119 of file pbx_dundi.c.

unsigned int dundi_result_id

Definition at line 3948 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 203 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4626 of file pbx_dundi.c.

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 184 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 182 of file pbx_dundi.c.

char email[80] [static]

Definition at line 196 of file pbx_dundi.c.

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

Definition at line 202 of file pbx_dundi.c.

int global_autokilltimeout = 0 [static]

Definition at line 187 of file pbx_dundi.c.

Definition at line 188 of file pbx_dundi.c.

int global_storehistory = 0 [static]

Definition at line 190 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 175 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 200 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 193 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 177 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 178 of file pbx_dundi.c.

char org[80] [static]

Definition at line 192 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 197 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 179 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 201 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 176 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 198 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 194 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 181 of file pbx_dundi.c.


Generated by  doxygen 1.6.2