Wed Aug 18 22:34:29 2010

Asterisk developer's documentation


pbx_dundi.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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


Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 92 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 75 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 76 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 77 of file pbx_dundi.c.

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

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

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

#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"

#define FORMAT   "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"

#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"

#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"

#define FORMAT   "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"

#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"

#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"

#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"

#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"

#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"

#define MAX_OPTS   128

Definition at line 4214 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 71 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

Definition at line 69 of file pbx_dundi.c.

Referenced by dundi_do_lookup(), dundi_exec(), dundi_helper(), dundi_lookup_thread(), dundi_precache_internal(), dundi_prop_precache(), dundifunc_read(), and precache_trans().

#define MAX_WEIGHT   59999

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

00082      {
00083    FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
00084    FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
00085    FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
00086    FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
00087    FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
00088    FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
00089    FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
00090 };

anonymous enum

Enumerator:
OPT_BYPASS_CACHE 

Definition at line 3858 of file pbx_dundi.c.

03858      {
03859    OPT_BYPASS_CACHE = (1 << 0),
03860 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4881 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4881 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3415 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03416 {
03417    struct dundi_transaction *trans;
03418 
03419    AST_LIST_LOCK(&peers);
03420    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03421       /* This will remove the transaction from the list */
03422       destroy_trans(trans, 0);
03423    }
03424    AST_LIST_UNLOCK(&peers);
03425 }

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

Definition at line 1917 of file pbx_dundi.c.

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

Referenced by handle_frame().

01918 {
01919    struct dundi_packet *pack;
01920 
01921    /* Ack transmitted packet corresponding to iseqno */
01922    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01923       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01924          destroy_packet(pack, 0);
01925          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01926             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01927             destroy_packets(&trans->lasttrans);
01928          }
01929          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01930          AST_SCHED_DEL(sched, trans->autokillid);
01931          return 1;
01932       }
01933    }
01934 
01935    return 0;
01936 }

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

Definition at line 4201 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

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

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

Definition at line 3370 of file pbx_dundi.c.

References dundi_peer::addr, ast_debug, ast_eid_to_str(), AST_LIST_INSERT_HEAD, ast_strlen_zero(), create_transaction(), dr, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, dundi_peer::maxms, dundi_transaction::parent, and dundi_transaction::ttl.

Referenced by build_transactions().

03371 {
03372    struct dundi_transaction *trans;
03373    int x;
03374    char eid_str[20];
03375    char eid_str2[20];
03376 
03377    /* Ignore if not registered */
03378    if (!p->addr.sin_addr.s_addr)
03379       return 0;
03380    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03381       return 0;
03382 
03383    if (ast_strlen_zero(dr->number))
03384       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);
03385    else
03386       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);
03387 
03388    trans = create_transaction(p);
03389    if (!trans)
03390       return -1;
03391    trans->parent = dr;
03392    trans->ttl = ttl;
03393    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03394       trans->eids[x] = *avoid[x];
03395    trans->eidcount = x;
03396    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03397    
03398    return 0;
03399 }

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

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

01197 {
01198    if (!trans->addr.sin_addr.s_addr)
01199       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01200    trans->us_eid = p->us_eid;
01201    trans->them_eid = p->eid;
01202    /* Enable encryption if appropriate */
01203    if (!ast_strlen_zero(p->inkey))
01204       ast_set_flag(trans, FLAG_ENCRYPT);  
01205    if (p->maxms) {
01206       trans->autokilltimeout = p->maxms;
01207       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01208       if (p->lastms > 1) {
01209          trans->retranstimer = p->lastms * 2;
01210          /* Keep it from being silly */
01211          if (trans->retranstimer < 150)
01212             trans->retranstimer = 150;
01213       }
01214       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01215          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01216    } else
01217       trans->autokilltimeout = global_autokilltimeout;
01218 }

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

Definition at line 3536 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03537 {
03538    /* Idea is that we're calculating a checksum which is independent of
03539       the order that the EID's are listed in */
03540    uint32_t acrc32 = 0;
03541    int x;
03542    for (x=0;avoid[x];x++) {
03543       /* Order doesn't matter */
03544       if (avoid[x+1]) {
03545          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03546       }
03547    }
03548    return acrc32;
03549 }

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

Definition at line 446 of file pbx_dundi.c.

References ast_random().

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

00447 {
00448    /* XXX Would be nice to be more random XXX */
00449    unsigned int *fluffy;
00450    int x;
00451    fluffy = (unsigned int *)(iv);
00452    for (x=0;x<4;x++)
00453       fluffy[x] = ast_random();
00454 }

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

Definition at line 4216 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdup, ast_strdupa, ast_strlen_zero(), DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, dundi_mapping::list, LOG_WARNING, map, MAX_OPTS, MAX_WEIGHT, and str2tech().

Referenced by set_config().

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

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

Definition at line 4371 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_eid_cmp(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_SCHED_DEL, dundi_peer::dead, destroy_permissions(), DUNDI_PORT, dundi_peer::eid, global_eid, hp, dundi_peer::include, dundi_peer::inkey, ast_variable::name, ast_variable::next, dundi_peer::outkey, dundi_peer::permit, populate_addr(), dundi_peer::registerid, sched, dundi_peer::us_eid, and ast_variable::value.

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

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

Definition at line 2007 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02008 {
02009    unsigned char tmp[16];
02010    char *s;
02011    build_iv(tmp);
02012    secret[0] = '\0';
02013    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02014    /* Eliminate potential bad characters */
02015    while((s = strchr(secret, ';'))) *s = '+';
02016    while((s = strchr(secret, '/'))) *s = '+';
02017    while((s = strchr(secret, ':'))) *s = '+';
02018    while((s = strchr(secret, '@'))) *s = '+';
02019 }

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

References append_transaction(), ast_clear_flag_nonstd, ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, cache_lookup(), dr, dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, has_permission(), dundi_peer::include, dundi_peer::list, dundi_peer::model, dundi_peer::order, pass, dundi_peer::pcmodel, dundi_peer::permit, and dundi_peer::us_eid.

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

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

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

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

01145 {
01146    char key[256];
01147    char eid_str[20];
01148    char eidroot_str[20];
01149    time_t now;
01150    int res=0;
01151    int res2=0;
01152    char eid_str_full[20];
01153    char tmp[256]="";
01154    int x;
01155 
01156    time(&now);
01157    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01158    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01159    ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01160    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32);
01161    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01162    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, 0);
01163    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01164    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01165    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01166    x = 0;
01167    if (!req->respcount) {
01168       while(!res2) {
01169          /* Look and see if we have a hint that would preclude us from looking at this
01170             peer for this number. */
01171          if (!(tmp[x] = req->number[x])) 
01172             break;
01173          x++;
01174          /* Check for hints */
01175          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32);
01176          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01177          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, 0);
01178          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01179          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01180          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01181          if (res2) {
01182             if (strlen(tmp) > strlen(req->hmd->exten)) {
01183                /* Update meta data if appropriate */
01184                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01185             }
01186          }
01187       }
01188       res |= res2;
01189    }
01190 
01191    return res;
01192 }

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

Definition at line 1072 of file pbx_dundi.c.

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

Referenced by cache_lookup().

01073 {
01074    char data[1024];
01075    char *ptr, *term, *src;
01076    int tech;
01077    struct ast_flags flags;
01078    int weight;
01079    int length;
01080    int z;
01081    char fs[256];
01082 
01083    /* Build request string */
01084    if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
01085       time_t timeout;
01086       ptr = data;
01087       if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
01088          int expiration = timeout - now;
01089          if (expiration > 0) {
01090             ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
01091             ptr += length + 1;
01092             while((sscanf(ptr, "%30d/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) == 3)) {
01093                ptr += length;
01094                term = strchr(ptr, '|');
01095                if (term) {
01096                   *term = '\0';
01097                   src = strrchr(ptr, '/');
01098                   if (src) {
01099                      *src = '\0';
01100                      src++;
01101                   } else
01102                      src = "";
01103                   ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", 
01104                      tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
01105                   /* Make sure it's not already there */
01106                   for (z=0;z<req->respcount;z++) {
01107                      if ((req->dr[z].techint == tech) &&
01108                          !strcmp(req->dr[z].dest, ptr)) 
01109                            break;
01110                   }
01111                   if (z == req->respcount) {
01112                      /* Copy into parent responses */
01113                      ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);   
01114                      req->dr[req->respcount].weight = weight;
01115                      req->dr[req->respcount].techint = tech;
01116                      req->dr[req->respcount].expiration = expiration;
01117                      dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
01118                      ast_eid_to_str(req->dr[req->respcount].eid_str, 
01119                         sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
01120                      ast_copy_string(req->dr[req->respcount].dest, ptr,
01121                         sizeof(req->dr[req->respcount].dest));
01122                      ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
01123                         sizeof(req->dr[req->respcount].tech));
01124                      req->respcount++;
01125                      ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK); 
01126                   } else if (req->dr[z].weight > weight)
01127                      req->dr[z].weight = weight;
01128                   ptr = term + 1;
01129                }
01130             }
01131             /* We found *something* cached */
01132             if (expiration < *lowexpiration)
01133                *lowexpiration = expiration;
01134             return 1;
01135          } else 
01136             ast_db_del("dundi/cache", key);
01137       } else 
01138          ast_db_del("dundi/cache", key);
01139    }
01140       
01141    return 0;
01142 }

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

Definition at line 801 of file pbx_dundi.c.

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

Referenced by handle_command_response().

00802 {
00803    int x;
00804    char key1[256];
00805    char key2[256];
00806    char data[1024];
00807    char eidpeer_str[20];
00808    char eidroot_str[20];
00809    time_t timeout;
00810 
00811    if (expiration < 1)  
00812       expiration = dundi_cache_time;
00813 
00814    /* Keep pushes a little longer, cut pulls a little short */
00815    if (push)
00816       expiration += 10;
00817    else
00818       expiration -= 10;
00819    if (expiration < 1)
00820       expiration = 1;
00821    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00822    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00823    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00824    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00825    /* Build request string */
00826    time(&timeout);
00827    timeout += expiration;
00828    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00829    for (x=start;x<req->respcount;x++) {
00830       /* Skip anything with an illegal pipe in it */
00831       if (strchr(req->dr[x].dest, '|'))
00832          continue;
00833       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", 
00834          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 
00835          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00836    }
00837    ast_db_put("dundi/cache", key1, data);
00838    ast_db_put("dundi/cache", key2, data);
00839    return 0;
00840 }

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

Definition at line 766 of file pbx_dundi.c.

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

Referenced by handle_command_response().

00767 {
00768    int unaffected;
00769    char key1[256];
00770    char key2[256];
00771    char eidpeer_str[20];
00772    char eidroot_str[20];
00773    char data[80];
00774    time_t timeout;
00775 
00776    if (expiration < 0)
00777       expiration = dundi_cache_time;
00778 
00779    /* Only cache hint if "don't ask" is there... */
00780    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))   
00781       return 0;
00782 
00783    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00784 
00785    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00786    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00787    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00788    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00789 
00790    time(&timeout);
00791    timeout += expiration;
00792    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00793    
00794    ast_db_put("dundi/cache", key1, data);
00795    ast_debug(1, "Caching hint at '%s'\n", key1);
00796    ast_db_put("dundi/cache", key2, data);
00797    ast_debug(1, "Caching hint at '%s'\n", key2);
00798    return 0;
00799 }

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3401 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03402 {
03403    struct dundi_transaction *trans;
03404 
03405    AST_LIST_LOCK(&peers);
03406    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03407       /* Orphan transaction from request */
03408       trans->parent = NULL;
03409       /* Send final cancel */
03410       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03411    }
03412    AST_LIST_UNLOCK(&peers);
03413 }

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

Definition at line 1395 of file pbx_dundi.c.

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

01396 {
01397    unsigned char dst[128];
01398    int res;
01399    struct ast_key *key, *skey;
01400    char eid_str[20];
01401    ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32);
01402    if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
01403       /* A match */
01404       return 1;
01405    } else if (!newkey || !newsig)
01406       return 0;
01407    if (!memcmp(peer->rxenckey, newkey, 128) &&
01408        !memcmp(peer->rxenckey + 128, newsig, 128)) {
01409       /* By definition, a match */
01410       return 1;
01411    }
01412    /* Decrypt key */
01413    key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01414    if (!key) {
01415       ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
01416          peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01417       return -1;
01418    }
01419 
01420    skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01421    if (!skey) {
01422       ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
01423          peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01424       return -1;
01425    }
01426 
01427    /* First check signature */
01428    res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
01429    if (res) 
01430       return 0;
01431 
01432    res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
01433    if (res != 16) {
01434       if (res >= 0)
01435          ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
01436       return 0;
01437    }
01438    /* Decrypted, passes signature */
01439    ast_debug(1, "Wow, new key combo passed signature and decrypt!\n");
01440    memcpy(peer->rxenckey, newkey, 128);
01441    memcpy(peer->rxenckey + 128, newsig, 128);
01442    peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
01443    ast_aes_decrypt_key(dst, &peer->them_dcx);
01444    ast_aes_encrypt_key(dst, &peer->them_ecx);
01445    return 1;
01446 }

static void check_password ( void   )  [static]

Definition at line 2074 of file pbx_dundi.c.

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

02075 {
02076    char oldsecret[80];
02077    time_t now;
02078    
02079    time(&now); 
02080 #if 0
02081    printf("%ld/%ld\n", now, rotatetime);
02082 #endif
02083    if ((now - rotatetime) >= 0) {
02084       /* Time to rotate keys */
02085       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02086       build_secret(cursecret, sizeof(cursecret));
02087       save_secret(cursecret, oldsecret);
02088    }
02089 }

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3522 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, and dundi_request::list.

Referenced by dundi_lookup_internal().

03523 {
03524    struct dundi_request *cur;
03525 
03526    AST_LIST_LOCK(&peers);
03527    AST_LIST_TRAVERSE(&requests, cur, list) {
03528       if (cur == dr)
03529          break;
03530    }
03531    AST_LIST_UNLOCK(&peers);
03532    
03533    return cur ? 1 : 0;
03534 }

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

Definition at line 2358 of file pbx_dundi.c.

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

Referenced by dundi_show_peer().

02359 {
02360    int which=0, len;
02361    char *ret = NULL;
02362    struct dundi_peer *p;
02363    char eid_str[20];
02364 
02365    if (pos != rpos)
02366       return NULL;
02367    AST_LIST_LOCK(&peers);
02368    len = strlen(word);
02369    AST_LIST_TRAVERSE(&peers, p, list) {
02370       const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02371       if (!strncasecmp(word, s, len) && ++which > state) {
02372          ret = ast_strdup(s);
02373          break;
02374       }
02375    }
02376    AST_LIST_UNLOCK(&peers);
02377    return ret;
02378 }

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

Definition at line 2877 of file pbx_dundi.c.

References dundi_peer::addr, apply_peer(), ast_calloc, AST_LIST_INSERT_HEAD, ast_set_flag, ast_tvnow(), DUNDI_DEFAULT_RETRANS_TIMER, FLAG_SENDFULLKEY, FLAG_STOREHIST, get_trans_id(), and dundi_peer::sentfullkey.

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

02878 {
02879    struct dundi_transaction *trans;
02880    int tid;
02881    
02882    /* Don't allow creation of transactions to non-registered peers */
02883    if (p && !p->addr.sin_addr.s_addr)
02884       return NULL;
02885    tid = get_trans_id();
02886    if (tid < 1)
02887       return NULL;
02888    if (!(trans = ast_calloc(1, sizeof(*trans))))
02889       return NULL;
02890 
02891    if (global_storehistory) {
02892       trans->start = ast_tvnow();
02893       ast_set_flag(trans, FLAG_STOREHIST);
02894    }
02895    trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02896    trans->autokillid = -1;
02897    if (p) {
02898       apply_peer(trans, p);
02899       if (!p->sentfullkey)
02900          ast_set_flag(trans, FLAG_SENDFULLKEY);
02901    }
02902    trans->strans = tid;
02903    AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02904    
02905    return trans;
02906 }

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

Definition at line 1287 of file pbx_dundi.c.

References ast_aes_decrypt.

Referenced by dundi_decrypt().

01288 {
01289    unsigned char lastblock[16];
01290    int x;
01291    memcpy(lastblock, iv, sizeof(lastblock));
01292    while(len > 0) {
01293       ast_aes_decrypt(src, dst, dcx);
01294       for (x=0;x<16;x++)
01295          dst[x] ^= lastblock[x];
01296       memcpy(lastblock, src, sizeof(lastblock));
01297       dst += 16;
01298       src += 16;
01299       len -= 16;
01300    }
01301    return 0;
01302 }

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

Definition at line 1448 of file pbx_dundi.c.

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

Referenced by handle_command_response().

01449 {
01450    struct permission *cur, *perm;
01451 
01452    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01453    
01454    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01455    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01456 
01457    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01458       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01459          continue;
01460 
01461       perm->allow = cur->allow;
01462       strcpy(perm->name, cur->name);
01463 
01464       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01465    }
01466 
01467    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01468       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01469          continue;
01470 
01471       perm->allow = cur->allow;
01472       strcpy(perm->name, cur->name);
01473 
01474       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01475    }
01476 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 4164 of file pbx_dundi.c.

References ast_free, and map.

Referenced by prune_mappings().

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

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

Definition at line 2924 of file pbx_dundi.c.

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

Referenced by ack_trans().

02925 {
02926    if (pack->parent)
02927       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02928    AST_SCHED_DEL(sched, pack->retransid);
02929    if (needfree)
02930       ast_free(pack);
02931 }

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

Definition at line 1906 of file pbx_dundi.c.

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

Referenced by ack_trans(), and handle_frame().

01907 {
01908    struct dundi_packet *pack;
01909    
01910    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01911       AST_SCHED_DEL(sched, pack->retransid);
01912       ast_free(pack);
01913    }
01914 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 4153 of file pbx_dundi.c.

References ast_free, AST_SCHED_DEL, destroy_permissions(), destroy_trans(), dundi_peer::include, dundi_peer::permit, dundi_peer::qualifyid, dundi_peer::registerid, dundi_peer::regtrans, and sched.

Referenced by prune_peers().

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

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

Definition at line 4145 of file pbx_dundi.c.

References ast_free, AST_LIST_REMOVE_HEAD, and permission::list.

Referenced by build_peer(), and destroy_peer().

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

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

Definition at line 2933 of file pbx_dundi.c.

References ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), dundi_peer::avgms, dundi_request::dcontext, DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, dundi_peer::lastms, dundi_peer::list, LOG_NOTICE, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::maxms, dundi_request::number, dundi_transaction::parent, dundi_peer::qualtrans, dundi_peer::qualtx, dundi_peer::regtrans, dundi_transaction::start, and dundi_transaction::them_eid.

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

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3255 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03256 {
03257    struct dundi_transaction *trans;
03258    AST_LIST_LOCK(&peers);
03259    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03260       dundi_discover(trans);
03261    }
03262    AST_LIST_UNLOCK(&peers);
03263    return 0;
03264 }

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

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

03111 {
03112    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03113    char eid_str[20];
03114    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03115       ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03116    trans->autokillid = -1;
03117    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03118    return 0;
03119 }

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

Definition at line 4316 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

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

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

Definition at line 4290 of file pbx_dundi.c.

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

04291 {
04292    struct dundi_ie_data ied;
04293    struct dundi_peer *peer = (struct dundi_peer *)data;
04294    char eid_str[20];
04295    char eid_str2[20];
04296    ast_debug(1, "Register us as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
04297    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04298    /* Destroy old transaction if there is one */
04299    if (peer->regtrans)
04300       destroy_trans(peer->regtrans, 0);
04301    peer->regtrans = create_transaction(peer);
04302    if (peer->regtrans) {
04303       ast_set_flag(peer->regtrans, FLAG_ISREG);
04304       memset(&ied, 0, sizeof(ied));
04305       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04306       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04307       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04308       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04309       
04310    } else
04311       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04312 
04313    return 0;
04314 }

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

Note:
Called with the peers list already locked

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

01222 {
01223    struct dundi_peer *peer = (struct dundi_peer *)data;
01224    char eid_str[20];
01225    ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01226    peer->registerexpire = -1;
01227    peer->lastms = 0;
01228    memset(&peer->addr, 0, sizeof(peer->addr));
01229    return 0;
01230 }

static void drds_destroy ( struct dundi_result_datastore drds  )  [static]

Definition at line 3941 of file pbx_dundi.c.

References ast_free.

Referenced by drds_destroy_cb(), and dundi_query_read().

03942 {
03943    ast_free(drds);
03944 }

static void drds_destroy_cb ( void *  data  )  [static]

Definition at line 3946 of file pbx_dundi.c.

References drds_destroy().

03947 {
03948    struct dundi_result_datastore *drds = data;
03949    drds_destroy(drds);
03950 }

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

Definition at line 364 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00365 {
00366    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00367 }

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

Definition at line 711 of file pbx_dundi.c.

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

Referenced by handle_command_response().

00712 {
00713    struct dundi_query_state *st;
00714    int totallen;
00715    int x;
00716    int skipfirst=0;
00717    char eid_str[20];
00718    char *s;
00719    pthread_t lookupthread;
00720 
00721    if (ies->eidcount > 1) {
00722       /* Since it is a requirement that the first EID is the authenticating host
00723          and the last EID is the root, it is permissible that the first and last EID
00724          could be the same.  In that case, we should go ahead copy only the "root" section
00725          since we will not need it for authentication. */
00726       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00727          skipfirst = 1;
00728    }
00729    totallen = sizeof(struct dundi_query_state);
00730    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00731    st = ast_calloc(1, totallen);
00732    if (st) {
00733       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00734       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00735       st->trans = trans;
00736       st->ttl = ies->ttl - 1;
00737       if (st->ttl < 0)
00738          st->ttl = 0;
00739       s = st->fluffy;
00740       for (x=skipfirst;ies->eids[x];x++) {
00741          st->eids[x-skipfirst] = (dundi_eid *)s;
00742          *st->eids[x-skipfirst] = *ies->eids[x];
00743          s += sizeof(dundi_eid);
00744       }
00745       ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00746 
00747       trans->thread = 1;
00748       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
00749          struct dundi_ie_data ied = { 0, };
00750          trans->thread = 0;
00751          ast_log(LOG_WARNING, "Unable to create thread!\n");
00752          ast_free(st);
00753          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00754          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00755          return -1;
00756       }
00757    } else {
00758       struct dundi_ie_data ied = { 0, };
00759       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00760       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00761       return -1;
00762    }
00763    return 0;
00764 }

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

Definition at line 989 of file pbx_dundi.c.

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

Referenced by handle_command_response().

00990 {
00991    struct dundi_query_state *st;
00992    int totallen;
00993    int x;
00994    struct dundi_ie_data ied;
00995    char *s;
00996    struct dundi_mapping *cur;
00997    int mapcount = 0;
00998    int skipfirst = 0;
00999    
01000    pthread_t lookupthread;
01001    totallen = sizeof(struct dundi_query_state);
01002    /* Count matching map entries */
01003    AST_LIST_TRAVERSE(&mappings, cur, list) {
01004       if (!strcasecmp(cur->dcontext, ccontext))
01005          mapcount++;
01006    }
01007    /* If no maps, return -1 immediately */
01008    if (!mapcount)
01009       return -1;
01010 
01011    if (ies->eidcount > 1) {
01012       /* Since it is a requirement that the first EID is the authenticating host
01013          and the last EID is the root, it is permissible that the first and last EID
01014          could be the same.  In that case, we should go ahead copy only the "root" section
01015          since we will not need it for authentication. */
01016       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01017          skipfirst = 1;
01018    }
01019 
01020    totallen += mapcount * sizeof(struct dundi_mapping);
01021    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01022    st = ast_calloc(1, totallen);
01023    if (st) {
01024       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
01025       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01026       st->trans = trans;
01027       st->ttl = ies->ttl - 1;
01028       st->nocache = ies->cbypass;
01029       if (st->ttl < 0)
01030          st->ttl = 0;
01031       s = st->fluffy;
01032       for (x=skipfirst;ies->eids[x];x++) {
01033          st->eids[x-skipfirst] = (dundi_eid *)s;
01034          *st->eids[x-skipfirst] = *ies->eids[x];
01035          st->directs[x-skipfirst] = ies->eid_direct[x];
01036          s += sizeof(dundi_eid);
01037       }
01038       /* Append mappings */
01039       x = 0;
01040       st->maps = (struct dundi_mapping *)s;
01041       AST_LIST_TRAVERSE(&mappings, cur, list) {
01042          if (!strcasecmp(cur->dcontext, ccontext)) {
01043             if (x < mapcount) {
01044                st->maps[x] = *cur;
01045                st->maps[x].list.next = NULL;
01046                x++;
01047             }
01048          }
01049       }
01050       st->nummaps = mapcount;
01051       ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
01052       trans->thread = 1;
01053       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) {
01054          trans->thread = 0;
01055          ast_log(LOG_WARNING, "Unable to create thread!\n");
01056          ast_free(st);
01057          memset(&ied, 0, sizeof(ied));
01058          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01059          dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01060          return -1;
01061       }
01062    } else {
01063       ast_log(LOG_WARNING, "Out of memory!\n");
01064       memset(&ied, 0, sizeof(ied));
01065       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01066       dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01067       return -1;
01068    }
01069    return 0;
01070 }

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

Definition at line 4561 of file pbx_dundi.c.

References chan, DUNDI_FLAG_CANMATCH, and dundi_helper().

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

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

Definition at line 271 of file pbx_dundi.c.

References ast_verbose.

Referenced by load_module().

00272 {
00273    if (dundidebug)
00274       ast_verbose("%s", data);
00275 }

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

Definition at line 1304 of file pbx_dundi.c.

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

01305 {
01306    int space = *dstlen;
01307    unsigned long bytes;
01308    struct dundi_hdr *h;
01309    unsigned char *decrypt_space;
01310    decrypt_space = alloca(srclen);
01311    if (!decrypt_space)
01312       return NULL;
01313    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01314    /* Setup header */
01315    h = (struct dundi_hdr *)dst;
01316    *h = *ohdr;
01317    bytes = space - 6;
01318    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01319       ast_debug(1, "Ouch, uncompress failed :(\n");
01320       return NULL;
01321    }
01322    /* Update length */
01323    *dstlen = bytes + 6;
01324    /* Return new header */
01325    return h;
01326 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3143 of file pbx_dundi.c.

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

Referenced by discover_transactions().

03144 {
03145    struct dundi_ie_data ied;
03146    int x;
03147    if (!trans->parent) {
03148       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03149       return -1;
03150    }
03151    memset(&ied, 0, sizeof(ied));
03152    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03153    if (!dundi_eid_zero(&trans->us_eid))
03154       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03155    for (x=0;x<trans->eidcount;x++)
03156       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03157    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03158    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03159    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03160    if (trans->parent->cbypass)
03161       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03162    if (trans->autokilltimeout)
03163       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03164    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03165 }

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

Definition at line 2196 of file pbx_dundi.c.

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

02197 {
02198    switch (cmd) {
02199    case CLI_INIT:
02200       e->command = "dundi [no] debug";
02201       e->usage = 
02202          "Usage: dundi [no] debug\n"
02203          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02204       return NULL;
02205    case CLI_GENERATE:
02206       return NULL;
02207    }
02208    if (a->argc < 2 || a->argc > 3)
02209       return CLI_SHOWUSAGE;
02210    if (a->argc == 2) {
02211       dundidebug = 1;
02212       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02213    } else {
02214       dundidebug = 0;
02215       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02216    }
02217    return CLI_SUCCESS;
02218 }

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

Definition at line 2397 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dr, dundi_flags2str(), dundi_lookup(), ast_cli_args::fd, MAX_RESULTS, sort_results(), and ast_cli_entry::usage.

02398 {
02399    int res;
02400    char tmp[256];
02401    char fs[80] = "";
02402    char *context;
02403    int x;
02404    int bypass = 0;
02405    struct dundi_result dr[MAX_RESULTS];
02406    struct timeval start;
02407    switch (cmd) {
02408    case CLI_INIT:
02409       e->command = "dundi lookup";
02410       e->usage =
02411          "Usage: dundi lookup <number>[@context] [bypass]\n"
02412          "       Lookup the given number within the given DUNDi context\n"
02413          "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
02414          "keyword is specified.\n";
02415       return NULL;
02416    case CLI_GENERATE:
02417       return NULL;
02418    }
02419 
02420    if ((a->argc < 3) || (a->argc > 4))
02421       return CLI_SHOWUSAGE;
02422    if (a->argc > 3) {
02423       if (!strcasecmp(a->argv[3], "bypass"))
02424          bypass=1;
02425       else
02426          return CLI_SHOWUSAGE;
02427    }
02428    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02429    context = strchr(tmp, '@');
02430    if (context) {
02431       *context = '\0';
02432       context++;
02433    }
02434    start = ast_tvnow();
02435    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02436    
02437    if (res < 0) 
02438       ast_cli(a->fd, "DUNDi lookup returned error.\n");
02439    else if (!res) 
02440       ast_cli(a->fd, "DUNDi lookup returned no results.\n");
02441    else
02442       sort_results(dr, res);
02443    for (x=0;x<res;x++) {
02444       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));
02445       ast_cli(a->fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02446    }
02447    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02448    return CLI_SUCCESS;
02449 }

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

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

02452 {
02453    int res;
02454    char tmp[256];
02455    char *context;
02456    struct timeval start;
02457    switch (cmd) {
02458    case CLI_INIT:
02459       e->command = "dundi precache";
02460       e->usage = 
02461          "Usage: dundi precache <number>[@context]\n"
02462          "       Lookup the given number within the given DUNDi context\n"
02463          "(or e164 if none is specified) and precaches the results to any\n"
02464          "upstream DUNDi push servers.\n";
02465       return NULL;
02466    case CLI_GENERATE:
02467       return NULL;
02468    }
02469    if ((a->argc < 3) || (a->argc > 3))
02470       return CLI_SHOWUSAGE;
02471    ast_copy_string(tmp, a->argv[2], sizeof(tmp));
02472    context = strchr(tmp, '@');
02473    if (context) {
02474       *context = '\0';
02475       context++;
02476    }
02477    start = ast_tvnow();
02478    res = dundi_precache(context, tmp);
02479    
02480    if (res < 0) 
02481       ast_cli(a->fd, "DUNDi precache returned error.\n");
02482    else if (!res) 
02483       ast_cli(a->fd, "DUNDi precache returned no error.\n");
02484    ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02485    return CLI_SUCCESS;
02486 }

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

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

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

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

Definition at line 2246 of file pbx_dundi.c.

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

02247 {
02248    switch (cmd) {
02249    case CLI_INIT:
02250       e->command = "dundi [no] store history";
02251       e->usage = 
02252          "Usage: dundi [no] store history\n"
02253          "       Enables/Disables storing of DUNDi requests and times for debugging\n"
02254          "purposes\n";
02255       return NULL;
02256    case CLI_GENERATE:
02257       return NULL;
02258    }
02259    if (a->argc < 3 || a->argc > 4)
02260       return CLI_SHOWUSAGE;
02261    
02262    if (a->argc == 3) {
02263       global_storehistory = 1;
02264       ast_cli(a->fd, "DUNDi History Storage Enabled\n");
02265    } else {
02266       global_storehistory = 0;
02267       ast_cli(a->fd, "DUNDi History Storage Disabled\n");
02268    }
02269    return CLI_SUCCESS;
02270 }

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

Definition at line 1328 of file pbx_dundi.c.

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

Referenced by dundi_send().

01329 {
01330    unsigned char *compress_space;
01331    int len;
01332    int res;
01333    unsigned long bytes;
01334    struct dundi_ie_data ied;
01335    struct dundi_peer *peer;
01336    unsigned char iv[16];
01337    len = pack->datalen + pack->datalen / 100 + 42;
01338    compress_space = alloca(len);
01339    if (compress_space) {
01340       memset(compress_space, 0, len);
01341       /* We care about everthing save the first 6 bytes of header */
01342       bytes = len;
01343       res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
01344       if (res != Z_OK) {
01345          ast_debug(1, "Ouch, compression failed!\n");
01346          return -1;
01347       }
01348       memset(&ied, 0, sizeof(ied));
01349       /* Say who we are */
01350       if (!pack->h->iseqno && !pack->h->oseqno) {
01351          /* Need the key in the first copy */
01352          if (!(peer = find_peer(&trans->them_eid))) 
01353             return -1;
01354          if (update_key(peer))
01355             return -1;
01356          if (!peer->sentfullkey)
01357             ast_set_flag(trans, FLAG_SENDFULLKEY); 
01358          /* Append key data */
01359          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
01360          if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
01361             dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
01362             dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
01363          } else {
01364             dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
01365          }
01366          /* Setup contexts */
01367          trans->ecx = peer->us_ecx;
01368          trans->dcx = peer->us_dcx;
01369 
01370          /* We've sent the full key */
01371          peer->sentfullkey = 1;
01372       }
01373       /* Build initialization vector */
01374       build_iv(iv);
01375       /* Add the field, rounded up to 16 bytes */
01376       dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
01377       /* Copy the data */
01378       if ((ied.pos + bytes) >= sizeof(ied.buf)) {
01379          ast_log(LOG_NOTICE, "Final packet too large!\n");
01380          return -1;
01381       }
01382       encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
01383       ied.pos += ((bytes + 15) / 16) * 16;
01384       /* Reconstruct header */
01385       pack->datalen = sizeof(struct dundi_hdr);
01386       pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
01387       pack->h->cmdflags = 0;
01388       memcpy(pack->h->ies, ied.buf, ied.pos);
01389       pack->datalen += ied.pos;
01390       return 0;
01391    }
01392    return -1;
01393 }

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

Definition at line 277 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00278 {
00279    ast_log(LOG_WARNING, "%s", data);
00280 }

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

Definition at line 4566 of file pbx_dundi.c.

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

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

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

Definition at line 4556 of file pbx_dundi.c.

References chan, DUNDI_FLAG_EXISTS, and dundi_helper().

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

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

Definition at line 2299 of file pbx_dundi.c.

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

02300 {
02301    int stats = 0;
02302    switch (cmd) {
02303    case CLI_INIT:
02304       e->command = "dundi flush [stats]";
02305       e->usage = 
02306          "Usage: dundi flush [stats]\n"
02307          "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
02308          "'stats' is present, clears timer statistics instead of normal\n"
02309          "operation.\n";
02310       return NULL;
02311    case CLI_GENERATE:
02312       return NULL;
02313    }
02314    if ((a->argc < 2) || (a->argc > 3))
02315       return CLI_SHOWUSAGE;
02316    if (a->argc > 2) {
02317       if (!strcasecmp(a->argv[2], "stats"))
02318          stats = 1;
02319       else
02320          return CLI_SHOWUSAGE;
02321    }
02322    if (stats) {
02323       /* Flush statistics */
02324       struct dundi_peer *p;
02325       int x;
02326       AST_LIST_LOCK(&peers);
02327       AST_LIST_TRAVERSE(&peers, p, list) {
02328          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02329             if (p->lookups[x])
02330                ast_free(p->lookups[x]);
02331             p->lookups[x] = NULL;
02332             p->lookuptimes[x] = 0;
02333          }
02334          p->avgms = 0;
02335       }
02336       AST_LIST_UNLOCK(&peers);
02337    } else {
02338       ast_db_deltree("dundi/cache", NULL);
02339       ast_cli(a->fd, "DUNDi Cache Flushed\n");
02340    }
02341    return CLI_SUCCESS;
02342 }

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

Definition at line 4517 of file pbx_dundi.c.

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

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

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

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

Definition at line 3121 of file pbx_dundi.c.

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

Referenced by dundi_discover().

03122 {
03123    struct dundi_peer *p;
03124    if (!ast_eid_cmp(eid, us)) {
03125       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03126       return;
03127    }
03128    AST_LIST_LOCK(&peers);
03129    AST_LIST_TRAVERSE(&peers, p, list) {
03130       if (!ast_eid_cmp(&p->eid, eid)) {
03131          if (has_permission(&p->include, context))
03132             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03133          else
03134             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03135          break;
03136       }
03137    }
03138    if (!p)
03139       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03140    AST_LIST_UNLOCK(&peers);
03141 }

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

References chan, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, and dundi_lookup_internal().

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

03654 {
03655    struct dundi_hint_metadata hmd;
03656    dundi_eid *avoid[1] = { NULL, };
03657    int direct[1] = { 0, };
03658    int expiration = dundi_cache_time;
03659    memset(&hmd, 0, sizeof(hmd));
03660    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03661    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03662 }

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 3551 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(), chan, check_request(), discover_transactions(), dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, LOG_WARNING, ast_channel::name, optimize_transactions(), register_request(), dundi_request::root_eid, and unregister_request().

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

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

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

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_eid_to_str(), ast_exists_extension(), AST_FLAGS_ALL, ast_ignore_pattern(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_var_delete(), dr, DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, ast_var_t::entries, ast_flags::flags, get_mapping_weight(), map, pbx_substitute_variables_varshead(), and tech2str().

Referenced by dundi_lookup_thread(), and precache_trans().

00487 {
00488    struct ast_flags flags = {0};
00489    int x;
00490    if (!ast_strlen_zero(map->lcontext)) {
00491       if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00492          ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00493       if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00494          ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00495       if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00496          ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00497       if (ast_ignore_pattern(map->lcontext, called_number))
00498          ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00499 
00500       /* Clearly we can't say 'don't ask' anymore if we found anything... */
00501       if (ast_test_flag(&flags, AST_FLAGS_ALL)) 
00502          ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00503 
00504       if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00505          /* Skip partial answers */
00506          ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00507       }
00508       if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00509          struct varshead headp;
00510          struct ast_var_t *newvariable;
00511          ast_set_flag(&flags, map->options & 0xffff);
00512          ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00513          dr[anscnt].techint = map->tech;
00514          dr[anscnt].weight = get_mapping_weight(map);
00515          dr[anscnt].expiration = dundi_cache_time;
00516          ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00517          dr[anscnt].eid = *us_eid;
00518          ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00519          if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00520             AST_LIST_HEAD_INIT_NOLOCK(&headp);
00521             newvariable = ast_var_assign("NUMBER", called_number);
00522             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00523             newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
00524             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00525             newvariable = ast_var_assign("SECRET", cursecret);
00526             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00527             newvariable = ast_var_assign("IPADDR", ipaddr);
00528             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00529             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00530             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00531                ast_var_delete(newvariable);
00532          } else
00533             dr[anscnt].dest[0] = '\0';
00534          anscnt++;
00535       } else {
00536          /* No answers...  Find the fewest number of digits from the
00537             number for which we have no answer. */
00538          char tmp[AST_MAX_EXTENSION + 1] = "";
00539          for (x = 0; x < (sizeof(tmp) - 1); x++) {
00540             tmp[x] = called_number[x];
00541             if (!tmp[x])
00542                break;
00543             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00544                /* Oops found something we can't match.  If this is longer
00545                   than the running hint, we have to consider it */
00546                if (strlen(tmp) > strlen(hmd->exten)) {
00547                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00548                }
00549                break;
00550             }
00551          }
00552       }
00553    }
00554    return anscnt;
00555 }

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

Definition at line 559 of file pbx_dundi.c.

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

Referenced by dundi_answer_query().

00560 {
00561    struct dundi_query_state *st = data;
00562    struct dundi_result dr[MAX_RESULTS];
00563    struct dundi_ie_data ied;
00564    struct dundi_hint_metadata hmd;
00565    char eid_str[20];
00566    int res, x;
00567    int ouranswers=0;
00568    int max = 999999;
00569    int expiration = dundi_cache_time;
00570 
00571    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00572          st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00573    memset(&ied, 0, sizeof(ied));
00574    memset(&dr, 0, sizeof(dr));
00575    memset(&hmd, 0, sizeof(hmd));
00576    /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
00577    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00578    for (x=0;x<st->nummaps;x++)
00579       ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00580    if (ouranswers < 0)
00581       ouranswers = 0;
00582    for (x=0;x<ouranswers;x++) {
00583       if (dr[x].weight < max)
00584          max = dr[x].weight;
00585    }
00586       
00587    if (max) {
00588       /* If we do not have a canonical result, keep looking */
00589       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);
00590       if (res > 0) {
00591          /* Append answer in result */
00592          ouranswers += res;
00593       } else {
00594          if ((res < -1) && (!ouranswers))
00595             dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00596       }
00597    }
00598    AST_LIST_LOCK(&peers);
00599    /* Truncate if "don't ask" isn't present */
00600    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00601       hmd.exten[0] = '\0';
00602    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00603       ast_debug(1, "Our transaction went away!\n");
00604       st->trans->thread = 0;
00605       destroy_trans(st->trans, 0);
00606    } else {
00607       for (x=0;x<ouranswers;x++) {
00608          /* Add answers */
00609          if (dr[x].expiration && (expiration > dr[x].expiration))
00610             expiration = dr[x].expiration;
00611          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00612       }
00613       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00614       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00615       dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00616       st->trans->thread = 0;
00617    }
00618    AST_LIST_UNLOCK(&peers);
00619    ast_free(st);
00620    return NULL;   
00621 }

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

Definition at line 4621 of file pbx_dundi.c.

References chan, DUNDI_FLAG_MATCHMORE, and dundi_helper().

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

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

Pre-cache to push upstream peers.

Definition at line 3797 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03798 {
03799    dundi_eid *avoid[1] = { NULL, };
03800    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03801 }

static void dundi_precache_full ( void   )  [static]

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

03701 {
03702    struct dundi_mapping *cur;
03703    struct ast_context *con;
03704    struct ast_exten *e;
03705 
03706    AST_LIST_TRAVERSE(&mappings, cur, list) {
03707       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03708       ast_rdlock_contexts();
03709       con = NULL;
03710       while ((con = ast_walk_contexts(con))) {
03711          if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
03712             continue;
03713          /* Found the match, now queue them all up */
03714          ast_rdlock_context(con);
03715          e = NULL;
03716          while ((e = ast_walk_context_extensions(con, e)))
03717             reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03718          ast_unlock_context(con);
03719       }
03720       ast_unlock_contexts();
03721    }
03722 }

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

Definition at line 3724 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, errno, dundi_mapping::list, LOG_NOTICE, LOG_WARNING, MAX_RESULTS, optimize_transactions(), precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

03725 {
03726    struct dundi_request dr;
03727    struct dundi_hint_metadata hmd;
03728    struct dundi_result dr2[MAX_RESULTS];
03729    struct timeval start;
03730    struct dundi_mapping *maps = NULL, *cur;
03731    int nummaps = 0;
03732    int foundanswers;
03733    int foundcache, skipped, ttlms, ms;
03734    if (!context)
03735       context = "e164";
03736    ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
03737 
03738    AST_LIST_LOCK(&peers);
03739    AST_LIST_TRAVERSE(&mappings, cur, list) {
03740       if (!strcasecmp(cur->dcontext, context))
03741          nummaps++;
03742    }
03743    if (nummaps) {
03744       maps = alloca(nummaps * sizeof(*maps));
03745       nummaps = 0;
03746       if (maps) {
03747          AST_LIST_TRAVERSE(&mappings, cur, list) {
03748             if (!strcasecmp(cur->dcontext, context))
03749                maps[nummaps++] = *cur;
03750          }
03751       }
03752    }
03753    AST_LIST_UNLOCK(&peers);
03754    if (!nummaps || !maps)
03755       return -1;
03756    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03757    memset(&dr2, 0, sizeof(dr2));
03758    memset(&dr, 0, sizeof(dr));
03759    memset(&hmd, 0, sizeof(hmd));
03760    dr.dr = dr2;
03761    ast_copy_string(dr.number, number, sizeof(dr.number));
03762    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03763    dr.maxcount = MAX_RESULTS;
03764    dr.expiration = dundi_cache_time;
03765    dr.hmd = &hmd;
03766    dr.pfds[0] = dr.pfds[1] = -1;
03767    if (pipe(dr.pfds) < 0) {
03768       ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno));
03769       return -1;
03770    }
03771    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03772    optimize_transactions(&dr, 0);
03773    foundanswers = 0;
03774    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03775    if (foundanswers) {
03776       if (dr.expiration > 0) 
03777          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03778       else
03779          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03780    }
03781    start = ast_tvnow();
03782    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03783       if (dr.pfds[0] > -1) {
03784          ms = 100;
03785          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03786       } else
03787          usleep(1);
03788    }
03789    cancel_request(&dr);
03790    if (dr.pfds[0] > -1) {
03791       close(dr.pfds[0]);
03792       close(dr.pfds[1]);
03793    }
03794    return 0;
03795 }

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

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

00624 {
00625    struct dundi_query_state *st = data;
00626    struct dundi_ie_data ied;
00627    struct dundi_hint_metadata hmd;
00628    char eid_str[20];
00629 
00630    ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00631       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00632    memset(&ied, 0, sizeof(ied));
00633 
00634    /* Now produce precache */
00635    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00636 
00637    AST_LIST_LOCK(&peers);
00638    /* Truncate if "don't ask" isn't present */
00639    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00640       hmd.exten[0] = '\0';
00641    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00642       ast_debug(1, "Our transaction went away!\n");
00643       st->trans->thread = 0;
00644       destroy_trans(st->trans, 0);
00645    } else {
00646       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00647       st->trans->thread = 0;
00648    }
00649    AST_LIST_UNLOCK(&peers);
00650    ast_free(st);
00651    return NULL;   
00652 }

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

Definition at line 842 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_clear_flag_nonstd, ast_copy_string(), ast_eid_to_str(), dundi_ies::called_context, dundi_ies::called_number, dundi_answer::data, dundi_result::dest, dundi_request::dr, dr, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_answer::eid, dundi_ies::expiration, dundi_answer::flags, dundi_request::hmd, MAX_RESULTS, dundi_request::maxcount, dundi_transaction::parent, dundi_answer::protocol, dundi_request::respcount, s, tech2str(), dundi_result::techint, dundi_result::weight, and dundi_answer::weight.

Referenced by handle_command_response().

00843 {
00844    struct dundi_query_state *st;
00845    int totallen;
00846    int x,z;
00847    struct dundi_ie_data ied;
00848    char *s;
00849    struct dundi_result dr2[MAX_RESULTS];
00850    struct dundi_request dr;
00851    struct dundi_hint_metadata hmd;
00852 
00853    struct dundi_mapping *cur;
00854    int mapcount;
00855    int skipfirst = 0;
00856    
00857    pthread_t lookupthread;
00858 
00859    memset(&dr2, 0, sizeof(dr2));
00860    memset(&dr, 0, sizeof(dr));
00861    memset(&hmd, 0, sizeof(hmd));
00862    
00863    /* Forge request structure to hold answers for cache */
00864    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00865    dr.dr = dr2;
00866    dr.maxcount = MAX_RESULTS;
00867    dr.expiration = dundi_cache_time;
00868    dr.hmd = &hmd;
00869    dr.pfds[0] = dr.pfds[1] = -1;
00870    trans->parent = &dr;
00871    ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
00872    ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
00873    
00874    for (x=0;x<ies->anscount;x++) {
00875       if (trans->parent->respcount < trans->parent->maxcount) {
00876          /* Make sure it's not already there */
00877          for (z=0;z<trans->parent->respcount;z++) {
00878             if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
00879                 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data)) 
00880                   break;
00881          }
00882          if (z == trans->parent->respcount) {
00883             /* Copy into parent responses */
00884             trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
00885             trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
00886             trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
00887             trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
00888             if (ies->expiration > 0)
00889                trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
00890             else
00891                trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
00892             ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 
00893                sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
00894                &ies->answers[x]->eid);
00895             ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
00896                sizeof(trans->parent->dr[trans->parent->respcount].dest));
00897                ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
00898                sizeof(trans->parent->dr[trans->parent->respcount].tech));
00899             trans->parent->respcount++;
00900             ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);   
00901          } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
00902             /* Update weight if appropriate */
00903             trans->parent->dr[z].weight = ies->answers[x]->weight;
00904          }
00905       } else
00906          ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
00907             trans->parent->number, trans->parent->dcontext);
00908 
00909    }
00910    /* Save all the results (if any) we had.  Even if no results, still cache lookup. */
00911    cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
00912    if (ies->hint)
00913       cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
00914 
00915    totallen = sizeof(struct dundi_query_state);
00916    /* Count matching map entries */
00917    mapcount = 0;
00918    AST_LIST_TRAVERSE(&mappings, cur, list) {
00919       if (!strcasecmp(cur->dcontext, ccontext))
00920          mapcount++;
00921    }
00922    
00923    /* If no maps, return -1 immediately */
00924    if (!mapcount)
00925       return -1;
00926 
00927    if (ies->eidcount > 1) {
00928       /* Since it is a requirement that the first EID is the authenticating host
00929          and the last EID is the root, it is permissible that the first and last EID
00930          could be the same.  In that case, we should go ahead copy only the "root" section
00931          since we will not need it for authentication. */
00932       if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00933          skipfirst = 1;
00934    }
00935 
00936    /* Prepare to run a query and then propagate that as necessary */
00937    totallen += mapcount * sizeof(struct dundi_mapping);
00938    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00939    st = ast_calloc(1, totallen);
00940    if (st) {
00941       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00942       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
00943       st->trans = trans;
00944       st->ttl = ies->ttl - 1;
00945       st->nocache = ies->cbypass;
00946       if (st->ttl < 0)
00947          st->ttl = 0;
00948       s = st->fluffy;
00949       for (x=skipfirst;ies->eids[x];x++) {
00950          st->eids[x-skipfirst] = (dundi_eid *)s;
00951          *st->eids[x-skipfirst] = *ies->eids[x];
00952          st->directs[x-skipfirst] = ies->eid_direct[x];
00953          s += sizeof(dundi_eid);
00954       }
00955       /* Append mappings */
00956       x = 0;
00957       st->maps = (struct dundi_mapping *)s;
00958       AST_LIST_TRAVERSE(&mappings, cur, list) {
00959          if (!strcasecmp(cur->dcontext, ccontext)) {
00960             if (x < mapcount) {
00961                st->maps[x] = *cur;
00962                st->maps[x].list.next = NULL;
00963                x++;
00964             }
00965          }
00966       }
00967       st->nummaps = mapcount;
00968       ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
00969       trans->thread = 1;
00970       if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
00971          trans->thread = 0;
00972          ast_log(LOG_WARNING, "Unable to create thread!\n");
00973          ast_free(st);
00974          memset(&ied, 0, sizeof(ied));
00975          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00976          dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00977          return -1;
00978       }
00979    } else {
00980       ast_log(LOG_WARNING, "Out of memory!\n");
00981       memset(&ied, 0, sizeof(ied));
00982       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00983       dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00984       return -1;
00985    }
00986    return 0;
00987 }

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3233 of file pbx_dundi.c.

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

Referenced by query_transactions().

03234 {
03235    struct dundi_ie_data ied;
03236    int x;
03237    if (!trans->parent) {
03238       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03239       return -1;
03240    }
03241    memset(&ied, 0, sizeof(ied));
03242    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03243    if (!dundi_eid_zero(&trans->us_eid))
03244       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03245    for (x=0;x<trans->eidcount;x++)
03246       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03247    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03248    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03249    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03250    if (trans->autokilltimeout)
03251       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03252    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03253 }

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

Retrieve information on a specific EID.

Definition at line 3850 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03851 {
03852    dundi_eid *avoid[1] = { NULL, };
03853    struct dundi_hint_metadata hmd;
03854    memset(&hmd, 0, sizeof(hmd));
03855    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03856 }

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

References ast_copy_string(), AST_LIST_EMPTY, ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), build_transactions(), dr, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, optimize_transactions(), and query_transactions().

Referenced by dundi_query_eid(), and dundi_query_thread().

03804 {
03805    int res;
03806    struct dundi_request dr;
03807    dundi_eid *rooteid=NULL;
03808    int x;
03809    int ttlms;
03810    int skipped=0;
03811    int foundcache=0;
03812    struct timeval start;
03813    
03814    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03815 
03816    for (x=0;avoid[x];x++)
03817       rooteid = avoid[x];
03818    /* Now perform real check */
03819    memset(&dr, 0, sizeof(dr));
03820    dr.hmd = hmd;
03821    dr.dei = dei;
03822    dr.pfds[0] = dr.pfds[1] = -1;
03823    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03824    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03825    if (rooteid)
03826       dr.root_eid = *rooteid;
03827    /* Create transactions */
03828    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03829 
03830    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03831       do this earlier because we didn't know if we were going to have transactions
03832       or not. */
03833    if (!ttl) {
03834       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03835       return 0;
03836    }
03837       
03838    /* Optimize transactions */
03839    optimize_transactions(&dr, 9999);
03840    /* Actually perform transactions */
03841    query_transactions(&dr);
03842    /* Wait for transaction to come back */
03843    start = ast_tvnow();
03844    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03845       usleep(1);
03846    res = dr.respcount;
03847    return res;
03848 }

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

Definition at line 3957 of file pbx_dundi.c.

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

03958 {
03959    struct ast_module_user *u;
03960    AST_DECLARE_APP_ARGS(args,
03961       AST_APP_ARG(number);
03962       AST_APP_ARG(context);
03963       AST_APP_ARG(options);
03964    );
03965    struct ast_flags opts = { 0, };
03966    char *parse;
03967    struct dundi_result_datastore *drds;
03968    struct ast_datastore *datastore;
03969 
03970    u = ast_module_user_add(chan);
03971 
03972    if (ast_strlen_zero(data)) {
03973       ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
03974       ast_module_user_remove(u);
03975       return -1;
03976    }
03977 
03978    if (!chan) {
03979       ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
03980       ast_module_user_remove(u);
03981       return -1;
03982    }
03983 
03984    parse = ast_strdupa(data);
03985 
03986    AST_STANDARD_APP_ARGS(args, parse);
03987    
03988    if (!ast_strlen_zero(args.options))
03989       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03990 
03991    if (ast_strlen_zero(args.context))
03992       args.context = "e164";
03993 
03994    if (!(drds = ast_calloc(1, sizeof(*drds)))) {
03995       ast_module_user_remove(u);
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       ast_module_user_remove(u);
04005       return -1;
04006    }
04007 
04008    datastore->data = drds;
04009 
04010    drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, 
04011       args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
04012 
04013    if (drds->num_results > 0)
04014       sort_results(drds->results, drds->num_results);
04015 
04016    ast_channel_lock(chan);
04017    ast_channel_datastore_add(chan, datastore);
04018    ast_channel_unlock(chan);
04019 
04020    ast_module_user_remove(u);
04021 
04022    return 0;
04023 }

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

Definition at line 656 of file pbx_dundi.c.

References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, FLAG_DEAD, dundi_query_state::reqeid, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

00657 {
00658    struct dundi_query_state *st = data;
00659    struct dundi_entity_info dei;
00660    struct dundi_ie_data ied;
00661    struct dundi_hint_metadata hmd;
00662    char eid_str[20];
00663    int res;
00664 
00665    ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00666       st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00667    memset(&ied, 0, sizeof(ied));
00668    memset(&dei, 0, sizeof(dei));
00669    memset(&hmd, 0, sizeof(hmd));
00670    if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00671       /* Ooh, it's us! */
00672       ast_debug(1, "Neat, someone look for us!\n");
00673       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00674       ast_copy_string(dei.org, org, sizeof(dei.org));
00675       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00676       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00677       ast_copy_string(dei.country, country, sizeof(dei.country));
00678       ast_copy_string(dei.email, email, sizeof(dei.email));
00679       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00680       res = 1;
00681    } else {
00682       /* If we do not have a canonical result, keep looking */
00683       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00684    }
00685    AST_LIST_LOCK(&peers);
00686    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00687       ast_debug(1, "Our transaction went away!\n");
00688       st->trans->thread = 0;
00689       destroy_trans(st->trans, 0);
00690    } else {
00691       if (res) {
00692          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00693          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00694          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00695          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00696          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00697          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00698          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00699          if (!ast_strlen_zero(dei.ipaddr))
00700             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00701       }
00702       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00703       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00704       st->trans->thread = 0;
00705    }
00706    AST_LIST_UNLOCK(&peers);
00707    ast_free(st);
00708    return NULL;   
00709 }

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

Definition at line 368 of file pbx_dundi.c.

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

Referenced by handle_frame().

00369 {
00370    struct {
00371       struct dundi_packet pack;
00372       struct dundi_hdr hdr;
00373    } tmp;
00374    struct dundi_transaction trans;
00375    /* Never respond to an INVALID with another INVALID */
00376    if (h->cmdresp == DUNDI_COMMAND_INVALID)
00377       return;
00378    memset(&tmp, 0, sizeof(tmp));
00379    memset(&trans, 0, sizeof(trans));
00380    memcpy(&trans.addr, sin, sizeof(trans.addr));
00381    tmp.hdr.strans = h->dtrans;
00382    tmp.hdr.dtrans = h->strans;
00383    tmp.hdr.iseqno = h->oseqno;
00384    tmp.hdr.oseqno = h->iseqno;
00385    tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00386    tmp.hdr.cmdflags = 0;
00387    tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00388    tmp.pack.datalen = sizeof(struct dundi_hdr);
00389    tmp.pack.parent = &trans;
00390    dundi_xmit(&tmp.pack);
00391 }

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

Definition at line 4037 of file pbx_dundi.c.

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

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

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

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

03017 {
03018    struct dundi_packet *pack = (struct dundi_packet *)data;
03019    int res;
03020    AST_LIST_LOCK(&peers);
03021    if (pack->retrans < 1) {
03022       pack->retransid = -1;
03023       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
03024          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
03025             ast_inet_ntoa(pack->parent->addr.sin_addr), 
03026             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
03027       destroy_trans(pack->parent, 1);
03028       res = 0;
03029    } else {
03030       /* Decrement retransmission, try again */
03031       pack->retrans--;
03032       dundi_xmit(pack);
03033       res = 1;
03034    }
03035    AST_LIST_UNLOCK(&peers);
03036    return res;
03037 }

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

Definition at line 3039 of file pbx_dundi.c.

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

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

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

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

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

02221 {
02222    switch (cmd) {
02223    case CLI_INIT:
02224       e->command = "dundi set debug {on|off}";
02225       e->usage = 
02226          "Usage: dundi set debug {on|off}\n"
02227          "       Enables/Disables dumping of DUNDi packets for debugging purposes\n";
02228       return NULL;
02229    case CLI_GENERATE:
02230       return NULL;
02231    }
02232 
02233    if (a->argc != e->args)
02234       return CLI_SHOWUSAGE;
02235 
02236    if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
02237       dundidebug = 1;
02238       ast_cli(a->fd, "DUNDi Debugging Enabled\n");
02239    } else {
02240       dundidebug = 0;
02241       ast_cli(a->fd, "DUNDi Debugging Disabled\n");
02242    }
02243    return CLI_SUCCESS;
02244 }

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

Definition at line 2735 of file pbx_dundi.c.

References ast_cli_args::argc, ast_cli(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, global_eid, and ast_cli_entry::usage.

02736 {
02737    char eid_str[20];
02738    switch (cmd) {
02739    case CLI_INIT:
02740       e->command = "dundi show entityid";
02741       e->usage =
02742          "Usage: dundi show entityid\n"
02743          "       Displays the global entityid for this host.\n";
02744       return NULL;
02745    case CLI_GENERATE:
02746       return NULL;
02747    }
02748    if (a->argc != 3)
02749       return CLI_SHOWUSAGE;
02750    AST_LIST_LOCK(&peers);
02751    ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02752    AST_LIST_UNLOCK(&peers);
02753    ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
02754    return CLI_SUCCESS;
02755 }

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

Definition at line 2789 of file pbx_dundi.c.

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

02790 {
02791 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02792 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02793    struct dundi_mapping *map;
02794    char fs[256];
02795    char weight[8];
02796    switch (cmd) {
02797    case CLI_INIT:
02798       e->command = "dundi show mappings";
02799       e->usage = 
02800          "Usage: dundi show mappings\n"
02801          "       Lists all known DUNDi mappings.\n";
02802       return NULL;
02803    case CLI_GENERATE:
02804       return NULL;
02805    }
02806    if (a->argc != 3)
02807       return CLI_SHOWUSAGE;
02808    AST_LIST_LOCK(&peers);
02809    ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02810    AST_LIST_TRAVERSE(&mappings, map, list) {
02811       snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map));
02812       ast_cli(a->fd, FORMAT, map->dcontext, weight,
02813          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02814          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02815    }
02816    AST_LIST_UNLOCK(&peers);
02817    return CLI_SUCCESS;
02818 #undef FORMAT
02819 #undef FORMAT2
02820 }

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

Definition at line 2538 of file pbx_dundi.c.

References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_strlen_zero(), dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_peer_helper(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, dundi_peer::include, dundi_peer::inkey, ast_cli_args::line, permission::list, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::model, model2str(), ast_cli_args::n, permission::name, dundi_peer::order, dundi_peer::outkey, dundi_peer::permit, ast_cli_args::pos, dundi_peer::registerid, ast_cli_entry::usage, and ast_cli_args::word.

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

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

Definition at line 2611 of file pbx_dundi.c.

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

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

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

Definition at line 2822 of file pbx_dundi.c.

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

02823 {
02824 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02825 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02826    struct dundi_precache_queue *qe;
02827    int h,m,s;
02828    time_t now;
02829    switch (cmd) {
02830    case CLI_INIT:
02831       e->command = "dundi show precache";
02832       e->usage = 
02833          "Usage: dundi show precache\n"
02834          "       Lists all known DUNDi scheduled precache updates.\n";
02835       return NULL;
02836    case CLI_GENERATE:
02837       return NULL;
02838    }
02839    if (a->argc != 3)
02840       return CLI_SHOWUSAGE;
02841    time(&now);
02842    ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
02843    AST_LIST_LOCK(&pcq);
02844    AST_LIST_TRAVERSE(&pcq, qe, list) {
02845       s = qe->expiration - now;
02846       h = s / 3600;
02847       s = s % 3600;
02848       m = s / 60;
02849       s = s % 60;
02850       ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
02851    }
02852    AST_LIST_UNLOCK(&pcq);
02853    
02854    return CLI_SUCCESS;
02855 #undef FORMAT
02856 #undef FORMAT2
02857 }

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

Definition at line 2757 of file pbx_dundi.c.

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

02758 {
02759 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02760 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02761    struct dundi_request *req;
02762    char eidstr[20];
02763    switch (cmd) {
02764    case CLI_INIT:
02765       e->command = "dundi show requests";
02766       e->usage = 
02767          "Usage: dundi show requests\n"
02768          "       Lists all known pending DUNDi requests.\n";
02769       return NULL;
02770    case CLI_GENERATE:
02771       return NULL;
02772    }
02773    if (a->argc != 3)
02774       return CLI_SHOWUSAGE;
02775    AST_LIST_LOCK(&peers);
02776    ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02777    AST_LIST_TRAVERSE(&requests, req, list) {
02778       ast_cli(a->fd, FORMAT, req->number, req->dcontext,
02779          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02780    }
02781    AST_LIST_UNLOCK(&peers);
02782    return CLI_SUCCESS;
02783 #undef FORMAT
02784 #undef FORMAT2
02785 }

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

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

02707 {
02708 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02709 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02710    struct dundi_transaction *trans;
02711    switch (cmd) {
02712    case CLI_INIT:
02713       e->command = "dundi show trans";
02714       e->usage = 
02715          "Usage: dundi show trans\n"
02716          "       Lists all known DUNDi transactions.\n";
02717       return NULL;
02718    case CLI_GENERATE:
02719       return NULL;
02720    }
02721    if (a->argc != 3)
02722       return CLI_SHOWUSAGE;
02723    AST_LIST_LOCK(&peers);
02724    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02725    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02726       ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02727          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02728    }
02729    AST_LIST_UNLOCK(&peers);
02730    return CLI_SUCCESS;
02731 #undef FORMAT
02732 #undef FORMAT2
02733 }

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

Definition at line 2272 of file pbx_dundi.c.

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02909 {
02910    int res;
02911    if (dundidebug)
02912       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02913    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02914    if (res < 0) {
02915       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02916          ast_inet_ntoa(pack->parent->addr.sin_addr),
02917          ntohs(pack->parent->addr.sin_port), strerror(errno));
02918    }
02919    if (res > 0)
02920       res = 0;
02921    return res;
02922 }

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

Definition at line 3866 of file pbx_dundi.c.

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

03867 {
03868    int results;
03869    int x;
03870    struct ast_module_user *u;
03871    struct dundi_result dr[MAX_RESULTS];
03872    AST_DECLARE_APP_ARGS(args,
03873       AST_APP_ARG(number);
03874       AST_APP_ARG(context);
03875       AST_APP_ARG(options);
03876    );
03877    char *parse;
03878    struct ast_flags opts = { 0, };
03879 
03880    buf[0] = '\0';
03881 
03882    if (ast_strlen_zero(num)) {
03883       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03884       return -1;
03885    }
03886 
03887    u = ast_module_user_add(chan);
03888 
03889    parse = ast_strdupa(num);
03890 
03891    AST_STANDARD_APP_ARGS(args, parse);
03892 
03893    if (!ast_strlen_zero(args.options)) {
03894       ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
03895    }
03896    if (ast_strlen_zero(args.context)) {
03897       args.context = "e164";
03898    }
03899 
03900    results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
03901    if (results > 0) {
03902       sort_results(dr, results);
03903       for (x = 0; x < results; x++) {
03904          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03905             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03906             break;
03907          }
03908       }
03909    }
03910 
03911    ast_module_user_remove(u);
03912 
03913    return 0;
03914 }

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

Definition at line 1271 of file pbx_dundi.c.

References ast_aes_encrypt.

Referenced by dundi_encrypt().

01272 {
01273    unsigned char curblock[16];
01274    int x;
01275    memcpy(curblock, iv, sizeof(curblock));
01276    while(len > 0) {
01277       for (x=0;x<16;x++)
01278          curblock[x] ^= src[x];
01279       ast_aes_encrypt(curblock, dst, ecx);
01280       memcpy(curblock, dst, sizeof(curblock)); 
01281       dst += 16;
01282       src += 16;
01283       len -= 16;
01284    }
01285    return 0;
01286 }

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

Definition at line 428 of file pbx_dundi.c.

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

00429 {
00430    struct dundi_peer *cur = NULL;
00431 
00432    if (!eid)
00433       eid = &empty_eid;
00434    
00435    AST_LIST_TRAVERSE(&peers, cur, list) {
00436       if (!ast_eid_cmp(&cur->eid,eid))
00437          break;
00438    }
00439 
00440    if (!cur && any_peer)
00441       cur = any_peer;
00442 
00443    return cur;
00444 }

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

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

00327 {
00328    struct dundi_transaction *trans;
00329 
00330    /* Look for an exact match first */
00331    AST_LIST_TRAVERSE(&alltrans, trans, all) {
00332       if (!inaddrcmp(&trans->addr, sin) && 
00333            ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
00334            ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
00335            if (hdr->strans)
00336               trans->dtrans = ntohs(hdr->strans) & 32767;
00337            return trans;
00338       }
00339    }
00340    
00341    switch(hdr->cmdresp & 0x7f) {
00342    case DUNDI_COMMAND_DPDISCOVER:
00343    case DUNDI_COMMAND_EIDQUERY:
00344    case DUNDI_COMMAND_PRECACHERQ:
00345    case DUNDI_COMMAND_REGREQ:
00346    case DUNDI_COMMAND_NULL:
00347    case DUNDI_COMMAND_ENCRYPT:
00348       if (!hdr->strans)
00349          break;
00350       /* Create new transaction */
00351       if (!(trans = create_transaction(NULL)))
00352          break;
00353       memcpy(&trans->addr, sin, sizeof(trans->addr));
00354       trans->dtrans = ntohs(hdr->strans) & 32767;
00355    default:
00356       break;
00357    }
00358    
00359    return trans;
00360 }

static int get_mapping_weight ( struct dundi_mapping map  )  [static]

Definition at line 472 of file pbx_dundi.c.

References buf, map, MAX_WEIGHT, and pbx_substitute_variables_helper().

Referenced by dundi_lookup_local(), and dundi_show_mappings().

00473 {
00474    char buf[32];
00475 
00476    buf[0] = 0;
00477    if (map->weightstr) {
00478       pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
00479       if (sscanf(buf, "%30d", &map->_weight) != 1)
00480          map->_weight = MAX_WEIGHT;
00481    }
00482 
00483    return map->_weight;
00484 }

static int get_trans_id ( void   )  [static]

Definition at line 393 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

00394 {
00395    struct dundi_transaction *t;
00396    int stid = (ast_random() % 32766) + 1;
00397    int tid = stid;
00398 
00399    do {
00400       AST_LIST_TRAVERSE(&alltrans, t, all) {
00401          if (t->strans == tid) 
00402             break;
00403       }
00404       if (!t)
00405          return tid;
00406       tid = (tid % 32766) + 1;
00407    } while (tid != stid);
00408 
00409    return 0;
00410 }

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

Definition at line 1478 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), AST_SCHED_DEL, ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verb, cache_save(), cache_save_hint(), dundi_ies::called_context, dundi_ies::called_number, dundi_ies::cause, dundi_hdr::cmdresp, dundi_hint::data, dundi_answer::data, dundi_request::dcontext, deep_copy_peer(), dundi_result::dest, do_register_expire(), dundi_request::dr, dundi_answer_entity(), dundi_answer_query(), DUNDI_CAUSE_GENERAL, DUNDI_CAUSE_NOAUTH, DUNDI_COMMAND_CANCEL, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_peer::dynamic, dundi_answer::eid, dundi_peer::eid, dundi_ies::eidcount, dundi_ies::eids, dundi_request::expiration, dundi_ies::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, dundi_answer::flags, has_permission(), dundi_ies::hint, dundi_request::hmd, dundi_hdr::ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, permission::list, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_peer::model, dundi_request::number, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_ie_data::pos, dundi_answer::protocol, qualify_peer(), dundi_peer::registerexpire, dundi_request::respcount, sched, tech2str(), dundi_result::techint, dundi_transaction::them_eid, dundi_peer::us_eid, dundi_transaction::us_eid, dundi_result::weight, and dundi_answer::weight.

Referenced by handle_frame().

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

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

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

01939 {
01940    struct dundi_transaction *trans;
01941    trans = find_transaction(h, sin);
01942    if (!trans) {
01943       dundi_reject(h, sin);
01944       return 0;
01945    }
01946    /* Got a transaction, see where this header fits in */
01947    if (h->oseqno == trans->iseqno) {
01948       /* Just what we were looking for...  Anything but ack increments iseqno */
01949       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
01950          /* If final, we're done */
01951          destroy_trans(trans, 0);
01952          return 0;
01953       }
01954       if (h->cmdresp != DUNDI_COMMAND_ACK) {
01955          trans->oiseqno = trans->iseqno;
01956          trans->iseqno++;
01957          handle_command_response(trans, h, datalen, 0);
01958       }
01959       if (trans->aseqno != trans->iseqno) {
01960          dundi_ack(trans, h->cmdresp & 0x80);
01961          trans->aseqno = trans->iseqno;
01962       }
01963       /* Delete any saved last transmissions */
01964       destroy_packets(&trans->lasttrans);
01965       if (h->cmdresp & 0x80) {
01966          /* Final -- destroy now */
01967          destroy_trans(trans, 0);
01968       }
01969    } else if (h->oseqno == trans->oiseqno) {
01970       /* Last incoming sequence number -- send ACK without processing */
01971       dundi_ack(trans, 0);
01972    } else {
01973       /* Out of window -- simply drop */
01974       ast_debug(1, "Dropping packet out of window!\n");
01975    }
01976    return 0;
01977 }

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

Definition at line 282 of file pbx_dundi.c.

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

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

00283 {
00284    struct permission *perm;
00285    int res = 0;
00286 
00287    AST_LIST_TRAVERSE(permlist, perm, list) {
00288       if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
00289          res = perm->allow;
00290    }
00291 
00292    return res;
00293 }

static int load_module ( void   )  [static]

Definition at line 4824 of file pbx_dundi.c.

References ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_netsock_set_qos(), ast_register_switch(), ast_verb, cli_dundi, dundi_debug_output(), dundi_error_output(), dundi_function, DUNDI_PORT, dundi_query_function, dundi_result_function, dundi_set_error(), dundi_set_output(), dundi_switch, errno, io, io_context_create(), LOG_ERROR, sched, sched_context_create(), set_config(), and start_network_thread().

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

static void load_password ( void   )  [static]

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

02036 {
02037    char *current=NULL;
02038    char *last=NULL;
02039    char tmp[256];
02040    time_t expired;
02041    
02042    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02043    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02044       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02045       current = strchr(tmp, ';');
02046       if (!current)
02047          current = tmp;
02048       else {
02049          *current = '\0';
02050          current++;
02051       };
02052       if ((time(NULL) - expired) < 0) {
02053          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02054             expired = time(NULL) + DUNDI_SECRET_TIME;
02055       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02056          last = current;
02057          current = NULL;
02058       } else {
02059          last = NULL;
02060          current = NULL;
02061       }
02062    }
02063    if (current) {
02064       /* Current key is still valid, just setup rotatation properly */
02065       ast_copy_string(cursecret, current, sizeof(cursecret));
02066       rotatetime = expired;
02067    } else {
02068       /* Current key is out of date, rotate or eliminate all together */
02069       build_secret(cursecret, sizeof(cursecret));
02070       save_secret(cursecret, last);
02071    }
02072 }

static void mark_mappings ( void   )  [static]

Definition at line 4134 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

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

static void mark_peers ( void   )  [static]

Definition at line 4124 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

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

static char* model2str ( int  model  )  [static]

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

02345 {
02346    switch(model) {
02347    case DUNDI_MODEL_INBOUND:
02348       return "Inbound";
02349    case DUNDI_MODEL_OUTBOUND:
02350       return "Outbound";
02351    case DUNDI_MODEL_SYMMETRIC:
02352       return "Symmetric";
02353    default:
02354       return "Unknown";
02355    }
02356 }

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

Definition at line 2091 of file pbx_dundi.c.

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

02092 {
02093    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
02094       from the network, and queue them for delivery to the channels */
02095    int res;
02096    /* Establish I/O callback for socket read */
02097    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02098    
02099    while (!dundi_shutdown) {
02100       res = ast_sched_wait(sched);
02101       if ((res > 1000) || (res < 0))
02102          res = 1000;
02103       res = ast_io_wait(io, res);
02104       if (res >= 0) {
02105          AST_LIST_LOCK(&peers);
02106          ast_sched_runq(sched);
02107          AST_LIST_UNLOCK(&peers);
02108       }
02109       check_password();
02110    }
02111 
02112    netthreadid = AST_PTHREADT_NULL;
02113    
02114    return NULL;
02115 }

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

Definition at line 3314 of file pbx_dundi.c.

References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, dr, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), dundi_peer::include, dundi_peer::list, dundi_peer::order, dundi_transaction::them_eid, and dundi_transaction::us_eid.

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

03315 {
03316    /* Minimize the message propagation through DUNDi by
03317       alerting the network to hops which should be not be considered */
03318    struct dundi_transaction *trans;
03319    struct dundi_peer *peer;
03320    dundi_eid tmp;
03321    int x;
03322    int needpush;
03323 
03324    AST_LIST_LOCK(&peers);
03325    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03326       /* Pop off the true root */
03327       if (trans->eidcount) {
03328          tmp = trans->eids[--trans->eidcount];
03329          needpush = 1;
03330       } else {
03331          tmp = trans->us_eid;
03332          needpush = 0;
03333       }
03334 
03335       AST_LIST_TRAVERSE(&peers, peer, list) {
03336          if (has_permission(&peer->include, dr->dcontext) && 
03337              ast_eid_cmp(&peer->eid, &trans->them_eid) &&
03338             (peer->order <= order)) {
03339             /* For each other transaction, make sure we don't
03340                ask this EID about the others if they're not
03341                already in the list */
03342             if (!ast_eid_cmp(&tmp, &peer->eid)) 
03343                x = -1;
03344             else {
03345                for (x=0;x<trans->eidcount;x++) {
03346                   if (!ast_eid_cmp(&trans->eids[x], &peer->eid))
03347                      break;
03348                }
03349             }
03350             if (x == trans->eidcount) {
03351                /* Nope not in the list, if needed, add us at the end since we're the source */
03352                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03353                   trans->eids[trans->eidcount++] = peer->eid;
03354                   /* Need to insert the real root (or us) at the bottom now as
03355                      a requirement now.  */
03356                   needpush = 1;
03357                }
03358             }
03359          }
03360       }
03361       /* If necessary, push the true root back on the end */
03362       if (needpush)
03363          trans->eids[trans->eidcount++] = tmp;
03364    }
03365    AST_LIST_UNLOCK(&peers);
03366 
03367    return 0;
03368 }

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

Definition at line 4347 of file pbx_dundi.c.

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

Referenced by build_peer().

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

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

Definition at line 3167 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, destroy_trans(), do_autokill(), dr, DUNDI_COMMAND_PRECACHERQ, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_eid(), dundi_ie_append_hint(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, MAX_RESULTS, dundi_request::number, dundi_transaction::parent, sched, dundi_transaction::them_eid, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by precache_transactions().

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

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

Definition at line 3266 of file pbx_dundi.c.

References ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_test_flag, destroy_trans(), dr, FLAG_DEAD, LOG_WARNING, precache_trans(), and dundi_transaction::thread.

Referenced by dundi_precache_internal().

03267 {
03268    struct dundi_transaction *trans;
03269 
03270    /* Mark all as "in thread" so they don't disappear */
03271    AST_LIST_LOCK(&peers);
03272    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03273       if (trans->thread)
03274          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03275       trans->thread = 1;
03276    }
03277    AST_LIST_UNLOCK(&peers);
03278 
03279    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03280       if (!ast_test_flag(trans, FLAG_DEAD))
03281          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03282    }
03283 
03284    /* Cleanup any that got destroyed in the mean time */
03285    AST_LIST_LOCK(&peers);
03286    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03287       trans->thread = 0;
03288       if (ast_test_flag(trans, FLAG_DEAD)) {
03289          ast_debug(1, "Our transaction went away!\n");
03290          /* This is going to remove the transaction from the dundi_request's list, as well
03291           * as the global transactions list */
03292          destroy_trans(trans, 0);
03293       }
03294    }
03295    AST_LIST_TRAVERSE_SAFE_END
03296    AST_LIST_UNLOCK(&peers);
03297 
03298    return 0;
03299 }

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

Definition at line 2117 of file pbx_dundi.c.

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

Referenced by start_network_thread().

02118 {
02119    struct ast_db_entry *db_entry, *db_tree;
02120    int striplen = sizeof("/dundi/cache");
02121    time_t now;
02122    
02123    while (!dundi_shutdown) {
02124       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
02125 
02126       time(&now);
02127 
02128       db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
02129       for (; db_entry; db_entry = db_entry->next) {
02130          time_t expiry;
02131 
02132          if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
02133             if (expiry < now) {
02134                ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
02135                ast_db_del("dundi/cache", db_entry->key + striplen);
02136             }
02137          }
02138       }
02139       ast_db_freetree(db_tree);
02140 
02141       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
02142       pthread_testcancel();
02143       sleep(60);
02144       pthread_testcancel();
02145    }
02146    
02147    clearcachethreadid = AST_PTHREADT_NULL;
02148    return NULL;
02149 }

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

Definition at line 2151 of file pbx_dundi.c.

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

Referenced by start_network_thread().

02152 {
02153    struct dundi_precache_queue *qe;
02154    time_t now;
02155    char context[256];
02156    char number[256];
02157    int run;
02158 
02159    while (!dundi_shutdown) {
02160       time(&now);
02161       run = 0;
02162       AST_LIST_LOCK(&pcq);
02163       if ((qe = AST_LIST_FIRST(&pcq))) {
02164          if (!qe->expiration) {
02165             /* Gone...  Remove... */
02166             AST_LIST_REMOVE_HEAD(&pcq, list);
02167             ast_free(qe);
02168          } else if (qe->expiration < now) {
02169             /* Process this entry */
02170             qe->expiration = 0;
02171             ast_copy_string(context, qe->context, sizeof(context));
02172             ast_copy_string(number, qe->number, sizeof(number));
02173             run = 1;
02174          }
02175       }
02176       AST_LIST_UNLOCK(&pcq);
02177       if (run) {
02178          dundi_precache(context, number);
02179       } else
02180          sleep(1);
02181    }
02182 
02183    precachethreadid = AST_PTHREADT_NULL;
02184 
02185    return NULL;
02186 }

static void prune_mappings ( void   )  [static]

Definition at line 4186 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, destroy_map(), dundi_mapping::list, and map.

Referenced by set_config(), and unload_module().

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

static void prune_peers ( void   )  [static]

Definition at line 4171 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_peer::dead, destroy_peer(), and dundi_peer::list.

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

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

Definition at line 4324 of file pbx_dundi.c.

References ast_sched_add(), AST_SCHED_DEL, ast_set_flag, ast_tvnow(), create_transaction(), destroy_trans(), do_qualify(), DUNDI_COMMAND_NULL, dundi_send(), FLAG_ISQUAL, dundi_peer::lastms, dundi_peer::maxms, dundi_peer::qualifyid, dundi_peer::qualtrans, dundi_peer::qualtx, and sched.

Referenced by do_qualify(), and handle_command_response().

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

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3301 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

03302 {
03303    struct dundi_transaction *trans;
03304 
03305    AST_LIST_LOCK(&peers);
03306    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03307       dundi_query(trans);
03308    }
03309    AST_LIST_UNLOCK(&peers);
03310 
03311    return 0;
03312 }

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

Definition at line 3485 of file pbx_dundi.c.

References ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::crc32, dundi_request::dcontext, dr, dundi_request::list, dundi_request::number, and dundi_request::root_eid.

Referenced by dundi_lookup_internal().

03486 {
03487    struct dundi_request *cur;
03488    int res=0;
03489    char eid_str[20];
03490    AST_LIST_LOCK(&peers);
03491    AST_LIST_TRAVERSE(&requests, cur, list) {
03492       ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03493          dr->dcontext, dr->number);
03494       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03495           !strcasecmp(cur->number, dr->number) &&
03496           (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03497          ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 
03498             cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03499          *pending = cur;
03500          res = 1;
03501          break;
03502       }
03503    }
03504    if (!res) {
03505       ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 
03506             dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03507       /* Go ahead and link us in since nobody else is searching for this */
03508       AST_LIST_INSERT_HEAD(&requests, dr, list);
03509       *pending = NULL;
03510    }
03511    AST_LIST_UNLOCK(&peers);
03512    return res;
03513 }

static int reload ( void   )  [static]

Definition at line 4814 of file pbx_dundi.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().

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

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

Definition at line 3664 of file pbx_dundi.c.

References ast_calloc, AST_LIST_FIRST, AST_LIST_INSERT_AFTER, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_precache_queue::context, dundi_precache_queue::expiration, len(), dundi_precache_queue::list, and dundi_precache_queue::number.

Referenced by dundi_precache_full(), and dundi_precache_internal().

03665 {
03666    int len;
03667    struct dundi_precache_queue *qe, *prev;
03668 
03669    AST_LIST_LOCK(&pcq);
03670    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03671       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03672          AST_LIST_REMOVE_CURRENT(list);
03673          break;
03674       }
03675    }
03676    AST_LIST_TRAVERSE_SAFE_END;
03677    if (!qe) {
03678       len = sizeof(*qe);
03679       len += strlen(number) + 1;
03680       len += strlen(context) + 1;
03681       if (!(qe = ast_calloc(1, len))) {
03682          AST_LIST_UNLOCK(&pcq);
03683          return;
03684       }
03685       strcpy(qe->number, number);
03686       qe->context = qe->number + strlen(number) + 1;
03687       strcpy(qe->context, context);
03688    }
03689    time(&qe->expiration);
03690    qe->expiration += expiration;
03691    if ((prev = AST_LIST_FIRST(&pcq))) {
03692       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03693          prev = AST_LIST_NEXT(prev, list);
03694       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03695    } else
03696       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03697    AST_LIST_UNLOCK(&pcq);
03698 }

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

Definition at line 2380 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02381 {
02382    const struct dundi_result *resa, *resb;
02383    resa = a;
02384    resb = b;
02385    if (resa->weight < resb->weight)
02386       return -1;
02387    if (resa->weight > resb->weight)
02388       return 1;
02389    return 0;
02390 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

00413 {
00414    int tid;
00415    tid = get_trans_id();
00416    if (tid < 1)
00417       return -1;
00418    trans->strans = tid;
00419    trans->dtrans = 0;
00420    trans->iseqno = 0;
00421    trans->oiseqno = 0;
00422    trans->oseqno = 0;
00423    trans->aseqno = 0;
00424    ast_clear_flag(trans, FLAG_FINAL);  
00425    return 0;
00426 }

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

Definition at line 2022 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02023 {
02024    char tmp[256];
02025    if (oldkey)
02026       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02027    else
02028       snprintf(tmp, sizeof(tmp), "%s", newkey);
02029    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02030    ast_db_put(secretpath, "secret", tmp);
02031    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02032    ast_db_put(secretpath, "secretexpiry", tmp);
02033 }

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

Definition at line 4636 of file pbx_dundi.c.

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

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

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

Definition at line 1979 of file pbx_dundi.c.

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

01980 {
01981    struct sockaddr_in sin;
01982    int res;
01983    struct dundi_hdr *h;
01984    char buf[MAX_PACKET_SIZE];
01985    socklen_t len = sizeof(sin);
01986    
01987    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
01988    if (res < 0) {
01989       if (errno != ECONNREFUSED)
01990          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
01991       return 1;
01992    }
01993    if (res < sizeof(struct dundi_hdr)) {
01994       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
01995       return 1;
01996    }
01997    buf[res] = '\0';
01998    h = (struct dundi_hdr *) buf;
01999    if (dundidebug)
02000       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
02001    AST_LIST_LOCK(&peers);
02002    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
02003    AST_LIST_UNLOCK(&peers);
02004    return 1;
02005 }

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

Definition at line 2392 of file pbx_dundi.c.

References rescomp().

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

02393 {
02394    qsort(results, count, sizeof(results[0]), rescomp);
02395 }

static int start_network_thread ( void   )  [static]

Definition at line 2188 of file pbx_dundi.c.

References ast_pthread_create_background, network_thread(), process_clearcache(), and process_precache().

static int str2tech ( char *  str  )  [static]

Definition at line 311 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

00312 {
00313    if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) 
00314       return DUNDI_PROTO_IAX;
00315    else if (!strcasecmp(str, "SIP"))
00316       return DUNDI_PROTO_SIP;
00317    else if (!strcasecmp(str, "H323"))
00318       return DUNDI_PROTO_H323;
00319    else
00320       return -1;
00321 }

static char* tech2str ( int  tech  )  [static]

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

00296 {
00297    switch(tech) {
00298    case DUNDI_PROTO_NONE:
00299       return "None";
00300    case DUNDI_PROTO_IAX:
00301       return "IAX2";
00302    case DUNDI_PROTO_SIP:
00303       return "SIP";
00304    case DUNDI_PROTO_H323:
00305       return "H323";
00306    default:
00307       return "Unknown";
00308    }
00309 }

static int unload_module ( void   )  [static]

Definition at line 4777 of file pbx_dundi.c.

References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_module_user_hangup_all, AST_PTHREADT_NULL, ast_unregister_switch(), cli_dundi, dundi_function, dundi_query_function, dundi_result_function, dundi_switch, io, io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), sched, and sched_context_destroy().

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

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3515 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, dr, and dundi_request::list.

Referenced by dundi_lookup_internal().

03516 {
03517    AST_LIST_LOCK(&peers);
03518    AST_LIST_REMOVE(&requests, dr, list);
03519    AST_LIST_UNLOCK(&peers);
03520 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1232 of file pbx_dundi.c.

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

Referenced by dundi_encrypt().

01233 {
01234    unsigned char key[16];
01235    struct ast_key *ekey, *skey;
01236    char eid_str[20];
01237    int res;
01238    if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
01239       build_iv(key);
01240       ast_aes_encrypt_key(key, &peer->us_ecx);
01241       ast_aes_decrypt_key(key, &peer->us_dcx);
01242       ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01243       if (!ekey) {
01244          ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
01245             peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01246          return -1;
01247       }
01248       skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01249       if (!skey) {
01250          ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
01251             peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01252          return -1;
01253       }
01254       if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
01255          ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
01256          return -1;
01257       }
01258       if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
01259          ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
01260          return -1;
01261       }
01262       peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
01263       peer->sentfullkey = 0;
01264       /* Looks good */
01265       time(&peer->keyexpire);
01266       peer->keyexpire += dundi_key_ttl;
01267    }
01268    return 0;
01269 }


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

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

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

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4881 of file pbx_dundi.c.

int authdebug = 0 [static]

Definition at line 108 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 105 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2861 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_dundi_do_debug_deprecated = { .handler = dundi_do_debug_deprecated , .summary = "Enable/Disable DUNDi debugging" ,__VA_ARGS__ } [static]

Definition at line 2859 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi_do_store_history_deprecated = { .handler = dundi_do_store_history_deprecated , .summary = "Enable/Disable DUNDi historic records" ,__VA_ARGS__ } [static]

Definition at line 2860 of file pbx_dundi.c.

char country[80] [static]

Definition at line 120 of file pbx_dundi.c.

Referenced by ind_load_module(), and SendDialTone().

char cursecret[80] [static]

Definition at line 124 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 114 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 116 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 111 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 110 of file pbx_dundi.c.

struct ast_custom_function dundi_query_function [static]

Definition at line 4025 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

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

Definition at line 3864 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundifunc_read().

struct ast_datastore_info dundi_result_datastore_info [static]

Initial value:

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

Definition at line 3952 of file pbx_dundi.c.

Referenced by dundi_query_read(), and dundi_result_read().

struct ast_custom_function dundi_result_function [static]

Definition at line 4111 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

unsigned int dundi_result_id

Definition at line 3933 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 128 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4626 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 109 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 107 of file pbx_dundi.c.

char email[80] [static]

Definition at line 121 of file pbx_dundi.c.

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

Definition at line 127 of file pbx_dundi.c.

Referenced by find_peer(), and set_config().

int global_autokilltimeout = 0 [static]

Definition at line 112 of file pbx_dundi.c.

dundi_eid global_eid [static]

Definition at line 113 of file pbx_dundi.c.

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

int global_storehistory = 0 [static]

Definition at line 115 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 100 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 125 of file pbx_dundi.c.

Referenced by realtime_peer(), and realtime_update_peer().

char locality[80] [static]

Definition at line 118 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 102 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 103 of file pbx_dundi.c.

char org[80] [static]

Definition at line 117 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 122 of file pbx_dundi.c.

Referenced by privacy_exec().

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 104 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 126 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 101 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 123 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 119 of file pbx_dundi.c.

unsigned int tos = 0 [static]

Definition at line 106 of file pbx_dundi.c.


Generated on Wed Aug 18 22:34:30 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7