Tue Aug 20 16:35:09 2013

Asterisk developer's documentation


pbx_dundi.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  alltrans
struct  dundi_hint_metadata
struct  dundi_mapping
struct  dundi_packet
struct  dundi_peer
struct  dundi_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_result_datastore
struct  dundi_transaction
struct  mappings
struct  packetlist
struct  pcq
struct  peers
struct  permission
struct  permissionlist
struct  requests

Defines

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)
#define DUNDI_MODEL_INBOUND   (1 << 0)
#define DUNDI_MODEL_OUTBOUND   (1 << 1)
#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME
#define DUNDI_TIMING_HISTORY   10
#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
#define FORMAT   "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
#define FORMAT   "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n"
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64
#define MAX_WEIGHT   59999

Enumerations

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

Functions

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

Variables

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

Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 168 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 151 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 152 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 153 of file pbx_dundi.c.

Referenced by build_peer(), and model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 173 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10

Keep times of last 10 lookups

Definition at line 156 of file pbx_dundi.c.

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

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

Definition at line 4191 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 147 of file pbx_dundi.c.

Referenced by handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 145 of file pbx_dundi.c.

#define MAX_WEIGHT   59999

Definition at line 149 of file pbx_dundi.c.

Referenced by build_mapping(), and get_mapping_weight().


Enumeration Type Documentation

anonymous enum
Enumerator:
FLAG_ISREG 

Transaction is register request

FLAG_DEAD 

Transaction is dead

FLAG_FINAL 

Transaction has final message sent

FLAG_ISQUAL 

Transaction is a qualification

FLAG_ENCRYPT 

Transaction is encrypted wiht ECX/DCX

FLAG_SENDFULLKEY 

Send full key on transaction

FLAG_STOREHIST 

Record historic performance

Definition at line 158 of file pbx_dundi.c.

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

anonymous enum
Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3877 of file pbx_dundi.c.

03877      {
03878    OPT_BYPASS_CACHE = (1 << 0),
03879 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4862 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4862 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

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

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

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

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

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

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

Definition at line 4178 of file pbx_dundi.c.

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

Referenced by build_peer().

04179 {
04180    struct permission *perm;
04181 
04182    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
04183       return;
04184 
04185    strcpy(perm->name, s);
04186    perm->allow = allow;
04187 
04188    AST_LIST_INSERT_TAIL(permlist, perm, list);
04189 }

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

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

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

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

Definition at line 1272 of file pbx_dundi.c.

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

Referenced by create_transaction(), and handle_command_response().

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

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

Definition at line 3556 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

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

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

Definition at line 522 of file pbx_dundi.c.

References ast_random().

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

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

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

Definition at line 4193 of file pbx_dundi.c.

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

Referenced by set_config().

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

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

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

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

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

Definition at line 2075 of file pbx_dundi.c.

References ast_base64encode(), and build_iv().

Referenced by check_password(), and load_password().

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

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

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

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

Definition at line 1220 of file pbx_dundi.c.

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

Referenced by build_transactions().

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

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

Definition at line 1148 of file pbx_dundi.c.

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

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

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

Definition at line 877 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

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

Definition at line 842 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

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

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

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

Definition at line 1466 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void check_password ( void   )  [static]

Definition at line 2142 of file pbx_dundi.c.

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

Referenced by network_thread().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3542 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

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

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

Definition at line 2376 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

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

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

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

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

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

Definition at line 1363 of file pbx_dundi.c.

References ast_aes_decrypt().

Referenced by dundi_decrypt().

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

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

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

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4141 of file pbx_dundi.c.

References ast_free, and dundi_mapping::weightstr.

Referenced by prune_mappings().

04142 {
04143    if (map->weightstr)
04144       ast_free(map->weightstr);
04145    ast_free(map);
04146 }

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

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

02943 {
02944    if (pack->parent)
02945       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02946    AST_SCHED_DEL(sched, pack->retransid);
02947    if (needfree)
02948       ast_free(pack);
02949 }

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

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

01975 {
01976    struct dundi_packet *pack;
01977 
01978    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01979       AST_SCHED_DEL(sched, pack->retransid);
01980       ast_free(pack);
01981    }
01982 }

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

Definition at line 4122 of file pbx_dundi.c.

References ast_free, and AST_LIST_REMOVE_HEAD.

Referenced by build_peer(), and destroy_peer().

04123 {
04124    struct permission *perm;
04125 
04126    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
04127       ast_free(perm);
04128 }

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

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

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

static int discover_transactions ( struct dundi_request dr  )  [static]

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

03274 {
03275    struct dundi_transaction *trans;
03276    AST_LIST_LOCK(&peers);
03277    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03278       dundi_discover(trans);
03279    }
03280    AST_LIST_UNLOCK(&peers);
03281    return 0;
03282 }

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

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

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

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

Definition at line 4293 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04294 {
04295    struct dundi_peer *peer = (struct dundi_peer *)data;
04296    peer->qualifyid = -1;
04297    qualify_peer(peer, 0);
04298    return 0;
04299 }

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

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

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

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

Definition at line 1297 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3947 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03948 {
03949    ast_free(drds);
03950 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3952 of file pbx_dundi.c.

References drds_destroy().

03953 {
03954    struct dundi_result_datastore *drds = data;
03955    drds_destroy(drds);
03956 }

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

Definition at line 440 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_command_response(), and handle_frame().

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

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

Definition at line 787 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 1065 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 4542 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

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

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

Definition at line 347 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

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

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

Definition at line 1380 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 1402 of file pbx_dundi.c.

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

Referenced by dundi_send().

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

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

Definition at line 353 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04538 {
04539    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04540 }

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

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

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

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

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

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

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

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

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

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

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

References abort_request(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), dundi_request::cbypass, check_request(), dundi_request::crc32, dundi_request::dcontext, discover_transactions(), dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, dundi_request::trans, and unregister_request().

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

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

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

Definition at line 562 of file pbx_dundi.c.

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_eid_to_str(), ast_exists_extension(), AST_FLAGS_ALL, ast_ignore_pattern(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_var_delete(), dundi_result::dest, dundi_mapping::dest, DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, dundi_result::eid, dundi_result::expiration, dundi_hint_metadata::exten, get_mapping_weight(), dundi_mapping::lcontext, dundi_mapping::options, pbx_substitute_variables_varshead(), dundi_result::tech, dundi_mapping::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 635 of file pbx_dundi.c.

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

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

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

Definition at line 4602 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04603 {
04604    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04605 }

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

Pre-cache to push upstream peers.

Definition at line 3816 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03817 {
03818    dundi_eid *avoid[1] = { NULL, };
03819    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03820 }

static void dundi_precache_full ( void   )  [static]

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

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

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

Definition at line 3744 of file pbx_dundi.c.

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

Referenced by dundi_precache(), and dundi_precache_thread().

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

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

Definition at line 699 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache().

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

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

Definition at line 918 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

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

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

Retrieve information on a specific EID.

Definition at line 3869 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03870 {
03871    dundi_eid *avoid[1] = { NULL, };
03872    struct dundi_hint_metadata hmd;
03873    memset(&hmd, 0, sizeof(hmd));
03874    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03875 }

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

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

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

Definition at line 3963 of file pbx_dundi.c.

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

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

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

Definition at line 732 of file pbx_dundi.c.

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

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

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

Definition at line 444 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_hdr::cmdresp, dundi_hdr::dtrans, DUNDI_COMMAND_INVALID, dundi_xmit(), dundi_hdr::iseqno, dundi_hdr::oseqno, and dundi_hdr::strans.

Referenced by handle_frame().

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

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

Definition at line 4027 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 2842 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache_queue::context, dundi_precache_queue::expiration, ast_cli_args::fd, FORMAT, FORMAT2, dundi_precache_queue::number, and ast_cli_entry::usage.

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

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

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

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

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

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

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

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

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

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

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

Definition at line 3885 of file pbx_dundi.c.

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

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

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

Definition at line 1347 of file pbx_dundi.c.

References ast_aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 504 of file pbx_dundi.c.

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

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

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

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

Definition at line 402 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 548 of file pbx_dundi.c.

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

Referenced by dundi_lookup_local(), and dundi_show_mappings().

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

static int get_trans_id ( void   )  [static]

Definition at line 469 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1549 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

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

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

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

Definition at line 358 of file pbx_dundi.c.

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

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

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

static int load_module ( void   )  [static]

Definition at line 4804 of file pbx_dundi.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_netsock_set_qos(), ast_register_switch(), ast_verb, dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, sched_context_create(), set_config(), and start_network_thread().

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

static void load_password ( void   )  [static]

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

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

static void mark_mappings ( void   )  [static]

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

04112 {
04113    struct dundi_mapping *map;
04114 
04115    AST_LIST_LOCK(&peers);
04116    AST_LIST_TRAVERSE(&mappings, map, list) {
04117       map->dead = 1;
04118    }
04119    AST_LIST_UNLOCK(&peers);
04120 }

static void mark_peers ( void   )  [static]

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

04102 {
04103    struct dundi_peer *peer;
04104    AST_LIST_LOCK(&peers);
04105    AST_LIST_TRAVERSE(&peers, peer, list) {
04106       peer->dead = 1;
04107    }
04108    AST_LIST_UNLOCK(&peers);
04109 }

static char* model2str ( int  model  )  [static]

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

02363 {
02364    switch(model) {
02365    case DUNDI_MODEL_INBOUND:
02366       return "Inbound";
02367    case DUNDI_MODEL_OUTBOUND:
02368       return "Outbound";
02369    case DUNDI_MODEL_SYMMETRIC:
02370       return "Symmetric";
02371    default:
02372       return "Unknown";
02373    }
02374 }

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

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

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

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

Definition at line 3332 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void prune_mappings ( void   )  [static]

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

04164 {
04165    struct dundi_mapping *map;
04166 
04167    AST_LIST_LOCK(&peers);
04168    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
04169       if (map->dead) {
04170          AST_LIST_REMOVE_CURRENT(list);
04171          destroy_map(map);
04172       }
04173    }
04174    AST_LIST_TRAVERSE_SAFE_END;
04175    AST_LIST_UNLOCK(&peers);
04176 }

static void prune_peers ( void   )  [static]

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

04149 {
04150    struct dundi_peer *peer;
04151 
04152    AST_LIST_LOCK(&peers);
04153    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
04154       if (peer->dead) {
04155          AST_LIST_REMOVE_CURRENT(list);
04156          destroy_peer(peer);
04157       }
04158    }
04159    AST_LIST_TRAVERSE_SAFE_END;
04160    AST_LIST_UNLOCK(&peers);
04161 }

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

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

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

static int query_transactions ( struct dundi_request dr  )  [static]

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

03320 {
03321    struct dundi_transaction *trans;
03322 
03323    AST_LIST_LOCK(&peers);
03324    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03325       dundi_query(trans);
03326    }
03327    AST_LIST_UNLOCK(&peers);
03328 
03329    return 0;
03330 }

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

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

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

static int reload ( void   )  [static]

Definition at line 4794 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

04795 {
04796    struct sockaddr_in sin;
04797 
04798    if (set_config("dundi.conf", &sin, 1))
04799       return AST_MODULE_LOAD_FAILURE;
04800 
04801    return AST_MODULE_LOAD_SUCCESS;
04802 }

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

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

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

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

Definition at line 2398 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02399 {
02400    const struct dundi_result *resa, *resb;
02401    resa = a;
02402    resb = b;
02403    if (resa->weight < resb->weight)
02404       return -1;
02405    if (resa->weight > resb->weight)
02406       return 1;
02407    return 0;
02408 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

Definition at line 488 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 2090 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

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

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

Definition at line 4616 of file pbx_dundi.c.

References any_peer, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_eid_default, ast_gethostbyname(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_str2tos(), ast_str_to_eid(), ast_true(), ast_variable_browse(), build_mapping(), build_peer(), CONFIG_STATUS_FILEINVALID, DEFAULT_MAXMS, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), find_peer(), hp, ast_variable::lineno, load_password(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mark_mappings(), mark_peers(), MAXHOSTNAMELEN, ast_variable::name, ast_variable::next, prune_mappings(), prune_peers(), and ast_variable::value.

Referenced by load_module(), and reload().

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

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

Definition at line 2047 of file pbx_dundi.c.

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

Referenced by network_thread().

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

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

Definition at line 2410 of file pbx_dundi.c.

References rescomp().

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

02411 {
02412    qsort(results, count, sizeof(results[0]), rescomp);
02413 }

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

Definition at line 387 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

Definition at line 371 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, DUNDI_PROTO_NONE, and DUNDI_PROTO_SIP.

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

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

static int unload_module ( void   )  [static]

Definition at line 4757 of file pbx_dundi.c.

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

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

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3535 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, and AST_LIST_UNLOCK.

Referenced by dundi_lookup_internal().

03536 {
03537    AST_LIST_LOCK(&peers);
03538    AST_LIST_REMOVE(&requests, dr, list);
03539    AST_LIST_UNLOCK(&peers);
03540 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1308 of file pbx_dundi.c.

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

Referenced by dundi_encrypt().

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


Variable Documentation

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

Definition at line 4862 of file pbx_dundi.c.

struct dundi_peer* any_peer [static]

Wildcard peer.

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

Definition at line 343 of file pbx_dundi.c.

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

Definition at line 4862 of file pbx_dundi.c.

int authdebug = 0 [static]

Definition at line 184 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 181 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2879 of file pbx_dundi.c.

char country[80] [static]

Definition at line 196 of file pbx_dundi.c.

Referenced by load_indications(), and SendDialTone().

char cursecret[80] [static]

Definition at line 200 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 190 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 192 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 187 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 186 of file pbx_dundi.c.

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

Definition at line 4022 of file pbx_dundi.c.

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

Definition at line 3883 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundifunc_read().

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

Definition at line 3958 of file pbx_dundi.c.

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

Definition at line 4096 of file pbx_dundi.c.

unsigned int dundi_result_id [static]

Definition at line 3939 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 204 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4607 of file pbx_dundi.c.

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 185 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 183 of file pbx_dundi.c.

char email[80] [static]

Definition at line 197 of file pbx_dundi.c.

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

Definition at line 203 of file pbx_dundi.c.

int global_autokilltimeout = 0 [static]

Definition at line 188 of file pbx_dundi.c.

Definition at line 189 of file pbx_dundi.c.

int global_storehistory = 0 [static]

Definition at line 191 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 176 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 201 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 194 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 178 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 179 of file pbx_dundi.c.

char org[80] [static]

Definition at line 193 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 198 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 180 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 202 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 177 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 199 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 195 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 182 of file pbx_dundi.c.


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1