Sat Aug 6 00:40:02 2011

Asterisk developer's documentation


pbx_dundi.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <zlib.h>
#include <sys/signal.h>
#include <pthread.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/options.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/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/aes.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_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 FLAG_DEAD   (1 << 1)
#define FLAG_ENCRYPT   (1 << 4)
#define FLAG_FINAL   (1 << 2)
#define FLAG_ISQUAL   (1 << 3)
#define FLAG_ISREG   (1 << 0)
#define FLAG_SENDFULLKEY   (1 << 5)
#define FLAG_STOREHIST   (1 << 6)
#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
#define FORMAT   "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
#define FORMAT   "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n"
#define KEY_IN   1
#define KEY_OUT   0
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64

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, 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 (char *name, 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_4 (const char *line, const char *word, int pos, int state)
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, aes_decrypt_ctx *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 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 int dundi_do_debug (int fd, int argc, char *argv[])
static int dundi_do_lookup (int fd, int argc, char *argv[])
static int dundi_do_precache (int fd, int argc, char *argv[])
static int dundi_do_query (int fd, int argc, char *argv[])
static int dundi_do_store_history (int fd, int argc, char *argv[])
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 int dundi_flush (int fd, int argc, char *argv[])
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 (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified. returns the number of results found or -1 on a hangup of teh channel.
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)
static int dundi_no_debug (int fd, int argc, char *argv[])
static int dundi_no_store_history (int fd, int argc, char *argv[])
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 void * dundi_query_thread (void *data)
static void dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin)
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 int dundi_show_entityid (int fd, int argc, char *argv[])
static int dundi_show_mappings (int fd, int argc, char *argv[])
static int dundi_show_peer (int fd, int argc, char *argv[])
static int dundi_show_peers (int fd, int argc, char *argv[])
static int dundi_show_precache (int fd, int argc, char *argv[])
static int dundi_show_requests (int fd, int argc, char *argv[])
static int dundi_show_trans (int fd, int argc, char *argv[])
static int dundi_xmit (struct dundi_packet *pack)
static int dundifunc_read (struct ast_channel *chan, char *cmd, char *num, char *buf, size_t len)
static int encrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_encrypt_ctx *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_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 void reset_global_eid (void)
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)
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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct dundi_peerany_peer
 Wildcard peer.
static const struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 0
static pthread_t clearcachethreadid = AST_PTHREADT_NULL
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
static char debug_usage []
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 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 char flush_usage []
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 char lookup_usage []
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char no_debug_usage []
static char no_store_history_usage []
static char org [80]
static char phone [80]
static char precache_usage []
static pthread_t precachethreadid = AST_PTHREADT_NULL
static char query_usage []
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static char show_entityid_usage []
static char show_mappings_usage []
static char show_peer_usage []
static char show_peers_usage []
static char show_precache_usage []
static char show_requests_usage []
static char show_trans_usage []
static char stateprov [80]
static char store_history_usage []
static 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 99 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 84 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

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

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

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

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

#define FLAG_DEAD   (1 << 1)

Transaction is dead

Definition at line 92 of file pbx_dundi.c.

Referenced by dundi_lookup_thread(), dundi_precache_thread(), dundi_query_thread(), and precache_transactions().

#define FLAG_ENCRYPT   (1 << 4)

Transaction is encrypted wiht ECX/DCX

Definition at line 95 of file pbx_dundi.c.

Referenced by apply_peer(), dundi_send(), and handle_command_response().

#define FLAG_FINAL   (1 << 2)

Transaction has final message sent

Definition at line 93 of file pbx_dundi.c.

Referenced by dundi_send(), handle_frame(), and reset_transaction().

#define FLAG_ISQUAL   (1 << 3)

Transaction is a qualification

Definition at line 94 of file pbx_dundi.c.

Referenced by destroy_trans(), dundi_rexmit(), and qualify_peer().

#define FLAG_ISREG   (1 << 0)

Transaction is register request

Definition at line 91 of file pbx_dundi.c.

Referenced by destroy_trans(), and do_register().

#define FLAG_SENDFULLKEY   (1 << 5)

Send full key on transaction

Definition at line 96 of file pbx_dundi.c.

Referenced by create_transaction(), and dundi_encrypt().

#define FLAG_STOREHIST   (1 << 6)

Record historic performance

Definition at line 97 of file pbx_dundi.c.

Referenced by create_transaction(), and destroy_trans().

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

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

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

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

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

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

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

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

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

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

#define KEY_IN   1

Definition at line 108 of file pbx_dundi.c.

#define KEY_OUT   0

Definition at line 107 of file pbx_dundi.c.

#define MAX_OPTS   128

Definition at line 4005 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 82 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4685 of file pbx_dundi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4685 of file pbx_dundi.c.

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3405 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03406 {
03407    struct dundi_transaction *trans;
03408 
03409    AST_LIST_LOCK(&peers);
03410    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03411       /* This will remove the transaction from the list */
03412       destroy_trans(trans, 0);
03413    }
03414    AST_LIST_UNLOCK(&peers);
03415 }

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

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

01977 {
01978    struct dundi_packet *pack;
01979 
01980    /* Ack transmitted packet corresponding to iseqno */
01981    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01982       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01983          destroy_packet(pack, 0);
01984          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01985             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01986             destroy_packets(&trans->lasttrans);
01987          }
01988          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01989          AST_SCHED_DEL(sched, trans->autokillid);
01990          return 1;
01991       }
01992    }
01993 
01994    return 0;
01995 }

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

Definition at line 3992 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_TAIL, and permission::list.

03993 {
03994    struct permission *perm;
03995 
03996    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03997       return;
03998 
03999    strcpy(perm->name, s);
04000    perm->allow = allow;
04001 
04002    AST_LIST_INSERT_TAIL(permlist, perm, list);
04003 }

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

Definition at line 3362 of file pbx_dundi.c.

References dundi_peer::addr, AST_LIST_INSERT_HEAD, ast_log(), ast_strlen_zero(), create_transaction(), dr, dundi_eid_to_str(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, LOG_DEBUG, dundi_peer::maxms, dundi_transaction::parent, dundi_transaction::parentlist, and dundi_transaction::ttl.

Referenced by build_transactions().

03363 {
03364    struct dundi_transaction *trans;
03365    int x;
03366    char eid_str[20];
03367    char eid_str2[20];
03368 
03369    /* Ignore if not registered */
03370    if (!p->addr.sin_addr.s_addr)
03371       return 0;
03372    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03373       return 0;
03374    if (ast_strlen_zero(dr->number))
03375       ast_log(LOG_DEBUG, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
03376    else
03377       ast_log(LOG_DEBUG, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
03378    trans = create_transaction(p);
03379    if (!trans)
03380       return -1;
03381    trans->parent = dr;
03382    trans->ttl = ttl;
03383    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03384       trans->eids[x] = *avoid[x];
03385    trans->eidcount = x;
03386    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03387    
03388    return 0;
03389 }

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

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

01254 {
01255    if (!trans->addr.sin_addr.s_addr)
01256       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01257    trans->us_eid = p->us_eid;
01258    trans->them_eid = p->eid;
01259    /* Enable encryption if appropriate */
01260    if (!ast_strlen_zero(p->inkey))
01261       ast_set_flag(trans, FLAG_ENCRYPT);  
01262    if (p->maxms) {
01263       trans->autokilltimeout = p->maxms;
01264       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01265       if (p->lastms > 1) {
01266          trans->retranstimer = p->lastms * 2;
01267          /* Keep it from being silly */
01268          if (trans->retranstimer < 150)
01269             trans->retranstimer = 150;
01270       }
01271       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01272          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01273    } else
01274       trans->autokilltimeout = global_autokilltimeout;
01275 }

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

Definition at line 3526 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03527 {
03528    /* Idea is that we're calculating a checksum which is independent of
03529       the order that the EID's are listed in */
03530    uint32_t acrc32 = 0;
03531    int x;
03532    for (x=0;avoid[x];x++) {
03533       /* Order doesn't matter */
03534       if (avoid[x+1]) {
03535          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03536       }
03537    }
03538    return acrc32;
03539 }

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

Definition at line 503 of file pbx_dundi.c.

References ast_random().

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

00504 {
00505    /* XXX Would be nice to be more random XXX */
00506    unsigned int *fluffy;
00507    int x;
00508    fluffy = (unsigned int *)(iv);
00509    for (x=0;x<4;x++)
00510       fluffy[x] = ast_random();
00511 }

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

Definition at line 4007 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), 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, str2tech(), and t.

Referenced by set_config().

04008 {
04009    char *t, *fields[MAX_OPTS];
04010    struct dundi_mapping *map;
04011    int x;
04012    int y;
04013 
04014    t = ast_strdupa(value);
04015       
04016    AST_LIST_TRAVERSE(&mappings, map, list) {
04017       /* Find a double match */
04018       if (!strcasecmp(map->dcontext, name) && 
04019          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
04020            (!value[strlen(map->lcontext)] || 
04021             (value[strlen(map->lcontext)] == ','))))
04022          break;
04023    }
04024    if (!map) {
04025       if (!(map = ast_calloc(1, sizeof(*map))))
04026          return;
04027       AST_LIST_INSERT_HEAD(&mappings, map, list);
04028       map->dead = 1;
04029    }
04030    map->options = 0;
04031    memset(fields, 0, sizeof(fields));
04032    x = 0;
04033    while (t && x < MAX_OPTS) {
04034       fields[x++] = t;
04035       t = strchr(t, ',');
04036       if (t) {
04037          *t = '\0';
04038          t++;
04039       }
04040    } /* Russell was here, arrrr! */
04041    if ((x == 1) && ast_strlen_zero(fields[0])) {
04042       /* Placeholder mapping */
04043       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04044       map->dead = 0;
04045    } else if (x >= 4) {
04046       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04047       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04048       if ((sscanf(fields[1], "%30d", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) {
04049          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04050          if ((map->tech = str2tech(fields[2]))) {
04051             map->dead = 0;
04052          }
04053       } else {
04054          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04055       }
04056       for (y = 4;y < x; y++) {
04057          if (!strcasecmp(fields[y], "nounsolicited"))
04058             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04059          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04060             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04061          else if (!strcasecmp(fields[y], "residential"))
04062             map->options |= DUNDI_FLAG_RESIDENTIAL;
04063          else if (!strcasecmp(fields[y], "commercial"))
04064             map->options |= DUNDI_FLAG_COMMERCIAL;
04065          else if (!strcasecmp(fields[y], "mobile"))
04066             map->options |= DUNDI_FLAG_MOBILE;
04067          else if (!strcasecmp(fields[y], "nopartial"))
04068             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04069          else
04070             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04071       }
04072    } else 
04073       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04074 }

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

Definition at line 4158 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_SCHED_DEL, dundi_peer::dead, destroy_permissions(), dundi_eid_cmp(), 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.

04159 {
04160    struct dundi_peer *peer;
04161    struct ast_hostent he;
04162    struct hostent *hp;
04163    dundi_eid testeid;
04164    int needregister=0;
04165    char eid_str[20];
04166 
04167    AST_LIST_LOCK(&peers);
04168    AST_LIST_TRAVERSE(&peers, peer, list) {
04169       if (!dundi_eid_cmp(&peer->eid, eid)) { 
04170          break;
04171       }
04172    }
04173    if (!peer) {
04174       /* Add us into the list */
04175       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04176          AST_LIST_UNLOCK(&peers);
04177          return;
04178       }
04179       peer->registerid = -1;
04180       peer->registerexpire = -1;
04181       peer->qualifyid = -1;
04182       peer->addr.sin_family = AF_INET;
04183       peer->addr.sin_port = htons(DUNDI_PORT);
04184       populate_addr(peer, eid);
04185       AST_LIST_INSERT_HEAD(&peers, peer, list);
04186    }
04187    peer->dead = 0;
04188    peer->eid = *eid;
04189    peer->us_eid = global_eid;
04190    destroy_permissions(&peer->permit);
04191    destroy_permissions(&peer->include);
04192    AST_SCHED_DEL(sched, peer->registerid);
04193    for (; v; v = v->next) {
04194       if (!strcasecmp(v->name, "inkey")) {
04195          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04196       } else if (!strcasecmp(v->name, "outkey")) {
04197          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04198       } else if (!strcasecmp(v->name, "port")) {
04199          peer->addr.sin_port = htons(atoi(v->value));
04200       } else if (!strcasecmp(v->name, "host")) {
04201          if (!strcasecmp(v->value, "dynamic")) {
04202             peer->dynamic = 1;
04203          } else {
04204             hp = ast_gethostbyname(v->value, &he);
04205             if (hp) {
04206                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04207                peer->dynamic = 0;
04208             } else {
04209                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04210                peer->dead = 1;
04211             }
04212          }
04213       } else if (!strcasecmp(v->name, "ustothem")) {
04214          if (!dundi_str_to_eid(&testeid, v->value))
04215             peer->us_eid = testeid;
04216          else
04217             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04218       } else if (!strcasecmp(v->name, "include")) {
04219          append_permission(&peer->include, v->value, 1);
04220       } else if (!strcasecmp(v->name, "permit")) {
04221          append_permission(&peer->permit, v->value, 1);
04222       } else if (!strcasecmp(v->name, "noinclude")) {
04223          append_permission(&peer->include, v->value, 0);
04224       } else if (!strcasecmp(v->name, "deny")) {
04225          append_permission(&peer->permit, v->value, 0);
04226       } else if (!strcasecmp(v->name, "register")) {
04227          needregister = ast_true(v->value);
04228       } else if (!strcasecmp(v->name, "order")) {
04229          if (!strcasecmp(v->value, "primary"))
04230             peer->order = 0;
04231          else if (!strcasecmp(v->value, "secondary"))
04232             peer->order = 1;
04233          else if (!strcasecmp(v->value, "tertiary"))
04234             peer->order = 2;
04235          else if (!strcasecmp(v->value, "quartiary"))
04236             peer->order = 3;
04237          else {
04238             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);
04239          }
04240       } else if (!strcasecmp(v->name, "qualify")) {
04241          if (!strcasecmp(v->value, "no")) {
04242             peer->maxms = 0;
04243          } else if (!strcasecmp(v->value, "yes")) {
04244             peer->maxms = DEFAULT_MAXMS;
04245          } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) {
04246             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04247                dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04248             peer->maxms = 0;
04249          }
04250       } else if (!strcasecmp(v->name, "model")) {
04251          if (!strcasecmp(v->value, "inbound"))
04252             peer->model = DUNDI_MODEL_INBOUND;
04253          else if (!strcasecmp(v->value, "outbound")) 
04254             peer->model = DUNDI_MODEL_OUTBOUND;
04255          else if (!strcasecmp(v->value, "symmetric"))
04256             peer->model = DUNDI_MODEL_SYMMETRIC;
04257          else if (!strcasecmp(v->value, "none"))
04258             peer->model = 0;
04259          else {
04260             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04261                v->value, v->lineno);
04262          }
04263       } else if (!strcasecmp(v->name, "precache")) {
04264          if (!strcasecmp(v->value, "inbound"))
04265             peer->pcmodel = DUNDI_MODEL_INBOUND;
04266          else if (!strcasecmp(v->value, "outbound")) 
04267             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04268          else if (!strcasecmp(v->value, "symmetric"))
04269             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04270          else if (!strcasecmp(v->value, "none"))
04271             peer->pcmodel = 0;
04272          else {
04273             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04274                v->value, v->lineno);
04275          }
04276       }
04277    }
04278    (*globalpcmode) |= peer->pcmodel;
04279    if (!peer->model && !peer->pcmodel) {
04280       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04281          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04282       peer->dead = 1;
04283    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04284       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04285          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04286       peer->dead = 1;
04287    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04288       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04289          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04290       peer->dead = 1;
04291    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04292       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04293          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04294    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04295       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", 
04296          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04297    } else { 
04298       if (needregister) {
04299          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04300       }
04301       qualify_peer(peer, 1);
04302    }
04303    AST_LIST_UNLOCK(&peers);
04304 }

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

Definition at line 2066 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02067 {
02068    unsigned char tmp[16];
02069    char *s;
02070    build_iv(tmp);
02071    secret[0] = '\0';
02072    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02073    /* Eliminate potential bad characters */
02074    while((s = strchr(secret, ';'))) *s = '+';
02075    while((s = strchr(secret, '/'))) *s = '+';
02076    while((s = strchr(secret, ':'))) *s = '+';
02077    while((s = strchr(secret, '@'))) *s = '+';
02078 }

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

References append_transaction(), ast_clear_flag_nonstd, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), cache_lookup(), dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, has_permission(), dundi_peer::include, dundi_peer::list, LOG_DEBUG, dundi_peer::model, dundi_peer::order, dundi_peer::pcmodel, dundi_peer::permit, and dundi_peer::us_eid.

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

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

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

Definition at line 1201 of file pbx_dundi.c.

References ast_copy_string(), cache_lookup_internal(), dundi_request::dcontext, dundi_eid_to_str(), 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().

01202 {
01203    char key[256];
01204    char eid_str[20];
01205    char eidroot_str[20];
01206    time_t now;
01207    int res=0;
01208    int res2=0;
01209    char eid_str_full[20];
01210    char tmp[256]="";
01211    int x;
01212 
01213    time(&now);
01214    dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
01215    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
01216    dundi_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
01217    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32);
01218    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01219    snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, 0);
01220    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01221    snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
01222    res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01223    x = 0;
01224    if (!req->respcount) {
01225       while(!res2) {
01226          /* Look and see if we have a hint that would preclude us from looking at this
01227             peer for this number. */
01228          if (!(tmp[x] = req->number[x])) 
01229             break;
01230          x++;
01231          /* Check for hints */
01232          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32);
01233          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01234          snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, 0);
01235          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01236          snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
01237          res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
01238          if (res2) {
01239             if (strlen(tmp) > strlen(req->hmd->exten)) {
01240                /* Update meta data if appropriate */
01241                ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
01242             }
01243          }
01244       }
01245       res |= res2;
01246    }
01247 
01248    return res;
01249 }

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

Definition at line 1129 of file pbx_dundi.c.

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

Referenced by cache_lookup().

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

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

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

00849 {
00850    int x;
00851    char key1[256];
00852    char key2[256];
00853    char data[1024];
00854    char eidpeer_str[20];
00855    char eidroot_str[20];
00856    time_t timeout;
00857 
00858    if (expiration < 1)  
00859       expiration = dundi_cache_time;
00860 
00861    /* Keep pushes a little longer, cut pulls a little short */
00862    if (push)
00863       expiration += 10;
00864    else
00865       expiration -= 10;
00866    if (expiration < 1)
00867       expiration = 1;
00868    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00869    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00870    snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
00871    snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
00872    /* Build request string */
00873    time(&timeout);
00874    timeout += expiration;
00875    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00876    for (x=start;x<req->respcount;x++) {
00877       /* Skip anything with an illegal pipe in it */
00878       if (strchr(req->dr[x].dest, '|'))
00879          continue;
00880       snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", 
00881          req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 
00882          dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
00883    }
00884    ast_db_put("dundi/cache", key1, data);
00885    ast_db_put("dundi/cache", key2, data);
00886    return 0;
00887 }

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

Definition at line 813 of file pbx_dundi.c.

References ast_db_put(), ast_log(), 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, LOG_DEBUG, and dundi_request::root_eid.

Referenced by handle_command_response().

00814 {
00815    int unaffected;
00816    char key1[256];
00817    char key2[256];
00818    char eidpeer_str[20];
00819    char eidroot_str[20];
00820    char data[80];
00821    time_t timeout;
00822 
00823    if (expiration < 0)
00824       expiration = dundi_cache_time;
00825 
00826    /* Only cache hint if "don't ask" is there... */
00827    if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))   
00828       return 0;
00829 
00830    unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
00831 
00832    dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
00833    dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
00834    snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
00835    snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
00836 
00837    time(&timeout);
00838    timeout += expiration;
00839    snprintf(data, sizeof(data), "%ld|", (long)(timeout));
00840    
00841    ast_db_put("dundi/cache", key1, data);
00842    ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key1);
00843    ast_db_put("dundi/cache", key2, data);
00844    ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key2);
00845    return 0;
00846 }

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3391 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03392 {
03393    struct dundi_transaction *trans;
03394 
03395    AST_LIST_LOCK(&peers);
03396    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03397       /* Orphan transaction from request */
03398       trans->parent = NULL;
03399       /* Send final cancel */
03400       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03401    }
03402    AST_LIST_UNLOCK(&peers);
03403 }

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

Definition at line 1452 of file pbx_dundi.c.

References aes_decrypt_key128(), aes_encrypt_key128(), ast_check_signature_bin, ast_decrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_eid_to_str(), dundi_peer::eid, dundi_peer::inkey, LOG_DEBUG, LOG_NOTICE, option_debug, dundi_peer::outkey, dundi_peer::rxenckey, dundi_peer::them_dcx, dundi_peer::them_ecx, and dundi_peer::them_keycrc32.

01453 {
01454    unsigned char dst[128];
01455    int res;
01456    struct ast_key *key, *skey;
01457    char eid_str[20];
01458    if (option_debug)
01459       ast_log(LOG_DEBUG, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32);
01460    if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
01461       /* A match */
01462       return 1;
01463    } else if (!newkey || !newsig)
01464       return 0;
01465    if (!memcmp(peer->rxenckey, newkey, 128) &&
01466        !memcmp(peer->rxenckey + 128, newsig, 128)) {
01467       /* By definition, a match */
01468       return 1;
01469    }
01470    /* Decrypt key */
01471    key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01472    if (!key) {
01473       ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
01474          peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01475       return -1;
01476    }
01477 
01478    skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01479    if (!skey) {
01480       ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
01481          peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01482       return -1;
01483    }
01484 
01485    /* First check signature */
01486    res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
01487    if (res) 
01488       return 0;
01489 
01490    res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
01491    if (res != 16) {
01492       if (res >= 0)
01493          ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
01494       return 0;
01495    }
01496    /* Decrypted, passes signature */
01497    ast_log(LOG_DEBUG, "Wow, new key combo passed signature and decrypt!\n");
01498    memcpy(peer->rxenckey, newkey, 128);
01499    memcpy(peer->rxenckey + 128, newsig, 128);
01500    peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
01501    aes_decrypt_key128(dst, &peer->them_dcx);
01502    aes_encrypt_key128(dst, &peer->them_ecx);
01503    return 1;
01504 }

static void check_password ( void   )  [static]

Definition at line 2133 of file pbx_dundi.c.

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

Referenced by network_thread().

02134 {
02135    char oldsecret[80];
02136    time_t now;
02137    
02138    time(&now); 
02139 #if 0
02140    printf("%ld/%ld\n", now, rotatetime);
02141 #endif
02142    if ((now - rotatetime) >= 0) {
02143       /* Time to rotate keys */
02144       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02145       build_secret(cursecret, sizeof(cursecret));
02146       save_secret(cursecret, oldsecret);
02147    }
02148 }

static int check_request ( struct dundi_request dr  )  [static]

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

03513 {
03514    struct dundi_request *cur;
03515 
03516    AST_LIST_LOCK(&peers);
03517    AST_LIST_TRAVERSE(&requests, cur, list) {
03518       if (cur == dr)
03519          break;
03520    }
03521    AST_LIST_UNLOCK(&peers);
03522    
03523    return cur ? 1 : 0;
03524 }

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

Definition at line 2361 of file pbx_dundi.c.

References complete_peer_helper().

02362 {
02363    return complete_peer_helper(line, word, pos, state, 3);
02364 }

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

Definition at line 2339 of file pbx_dundi.c.

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

Referenced by complete_peer_4().

02340 {
02341    int which=0, len;
02342    char *ret = NULL;
02343    struct dundi_peer *p;
02344    char eid_str[20];
02345 
02346    if (pos != rpos)
02347       return NULL;
02348    AST_LIST_LOCK(&peers);
02349    len = strlen(word);
02350    AST_LIST_TRAVERSE(&peers, p, list) {
02351       const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02352       if (!strncasecmp(word, s, len) && ++which > state) {
02353          ret = ast_strdup(s);
02354          break;
02355       }
02356    }
02357    AST_LIST_UNLOCK(&peers);
02358    return ret;
02359 }

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

Definition at line 2870 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::all, 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().

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

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

Definition at line 1344 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

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

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

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

01507 {
01508    struct permission *cur, *perm;
01509 
01510    memcpy(peer_dst, peer_src, sizeof(*peer_dst));
01511    
01512    memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
01513    memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
01514 
01515    AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
01516       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01517          continue;
01518 
01519       perm->allow = cur->allow;
01520       strcpy(perm->name, cur->name);
01521 
01522       AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
01523    }
01524 
01525    AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
01526       if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
01527          continue;
01528 
01529       perm->allow = cur->allow;
01530       strcpy(perm->name, cur->name);
01531 
01532       AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
01533    }
01534 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 3957 of file pbx_dundi.c.

References free, and map.

Referenced by prune_mappings().

03958 {
03959    free(map);
03960 }

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

Definition at line 2916 of file pbx_dundi.c.

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

Referenced by ack_trans().

02917 {
02918    if (pack->parent)
02919       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02920    AST_SCHED_DEL(sched, pack->retransid);
02921    if (needfree)
02922       free(pack);
02923 }

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

Definition at line 1965 of file pbx_dundi.c.

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

Referenced by ack_trans(), and handle_frame().

01966 {
01967    struct dundi_packet *pack;
01968    
01969    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01970       AST_SCHED_DEL(sched, pack->retransid);
01971       free(pack);
01972    }
01973 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 3946 of file pbx_dundi.c.

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

Referenced by prune_peers().

03947 {
03948    AST_SCHED_DEL(sched, peer->registerid);
03949    if (peer->regtrans)
03950       destroy_trans(peer->regtrans, 0);
03951    AST_SCHED_DEL(sched, peer->qualifyid);
03952    destroy_permissions(&peer->permit);
03953    destroy_permissions(&peer->include);
03954    free(peer);
03955 }

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

Definition at line 3938 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, free, and permission::list.

Referenced by build_peer(), and destroy_peer().

03939 {
03940    struct permission *perm;
03941 
03942    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03943       free(perm);
03944 }

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

Definition at line 2925 of file pbx_dundi.c.

References 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_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, free, 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().

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3247 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, dundi_discover(), and dundi_transaction::parentlist.

Referenced by dundi_lookup_internal().

03248 {
03249    struct dundi_transaction *trans;
03250    AST_LIST_LOCK(&peers);
03251    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03252       dundi_discover(trans);
03253    }
03254    AST_LIST_UNLOCK(&peers);
03255    return 0;
03256 }

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

Definition at line 3102 of file pbx_dundi.c.

References ast_log(), dundi_transaction::autokillid, destroy_trans(), dundi_eid_to_str(), LOG_NOTICE, and dundi_transaction::them_eid.

Referenced by dundi_discover(), dundi_query(), and precache_trans().

03103 {
03104    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03105    char eid_str[20];
03106    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03107       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03108    trans->autokillid = -1;
03109    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03110    return 0;
03111 }

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

Definition at line 4103 of file pbx_dundi.c.

References qualify_peer(), and dundi_peer::qualifyid.

Referenced by qualify_peer().

04104 {
04105    struct dundi_peer *peer = (struct dundi_peer *)data;
04106    peer->qualifyid = -1;
04107    qualify_peer(peer, 0);
04108    return 0;
04109 }

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

Definition at line 4077 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), destroy_trans(), DUNDI_COMMAND_REGREQ, DUNDI_DEFAULT_VERSION, dundi_eid_to_str(), 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_DEBUG, LOG_NOTICE, dundi_peer::registerid, dundi_peer::regtrans, sched, dundi_transaction::us_eid, and dundi_peer::us_eid.

04078 {
04079    struct dundi_ie_data ied;
04080    struct dundi_peer *peer = (struct dundi_peer *)data;
04081    char eid_str[20];
04082    char eid_str2[20];
04083    ast_log(LOG_DEBUG, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
04084    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04085    /* Destroy old transaction if there is one */
04086    if (peer->regtrans)
04087       destroy_trans(peer->regtrans, 0);
04088    peer->regtrans = create_transaction(peer);
04089    if (peer->regtrans) {
04090       ast_set_flag(peer->regtrans, FLAG_ISREG);
04091       memset(&ied, 0, sizeof(ied));
04092       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04093       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04094       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04095       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04096       
04097    } else
04098       ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04099 
04100    return 0;
04101 }

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

Note:
Called with the peers list already locked

Definition at line 1278 of file pbx_dundi.c.

References dundi_peer::addr, ast_log(), dundi_eid_to_str(), dundi_peer::eid, dundi_peer::lastms, LOG_DEBUG, and dundi_peer::registerexpire.

Referenced by handle_command_response(), and populate_addr().

01279 {
01280    struct dundi_peer *peer = (struct dundi_peer *)data;
01281    char eid_str[20];
01282    ast_log(LOG_DEBUG, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01283    peer->registerexpire = -1;
01284    peer->lastms = 0;
01285    memset(&peer->addr, 0, sizeof(peer->addr));
01286    return 0;
01287 }

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

Definition at line 376 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00377 {
00378    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00379 }

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

Definition at line 753 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), ast_log(), ast_pthread_create, dundi_query_state::called_context, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_query_thread(), dundi_send(), dundi_query_state::eids, dundi_query_state::fluffy, free, ies, LOG_DEBUG, LOG_WARNING, dundi_query_state::reqeid, s, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

Referenced by handle_command_response().

00754 {
00755    struct dundi_query_state *st;
00756    int totallen;
00757    int x;
00758    int skipfirst=0;
00759    struct dundi_ie_data ied;
00760    char eid_str[20];
00761    char *s;
00762    pthread_t lookupthread;
00763    pthread_attr_t attr;
00764    if (ies->eidcount > 1) {
00765       /* Since it is a requirement that the first EID is the authenticating host
00766          and the last EID is the root, it is permissible that the first and last EID
00767          could be the same.  In that case, we should go ahead copy only the "root" section
00768          since we will not need it for authentication. */
00769       if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00770          skipfirst = 1;
00771    }
00772    totallen = sizeof(struct dundi_query_state);
00773    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00774    st = ast_calloc(1, totallen);
00775    if (st) {
00776       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00777       memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00778       st->trans = trans;
00779       st->ttl = ies->ttl - 1;
00780       if (st->ttl < 0)
00781          st->ttl = 0;
00782       s = st->fluffy;
00783       for (x=skipfirst;ies->eids[x];x++) {
00784          st->eids[x-skipfirst] = (dundi_eid *)s;
00785          *st->eids[x-skipfirst] = *ies->eids[x];
00786          s += sizeof(dundi_eid);
00787       }
00788       ast_log(LOG_DEBUG, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00789       pthread_attr_init(&attr);
00790       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00791       trans->thread = 1;
00792       if (ast_pthread_create(&lookupthread, &attr, dundi_query_thread, st)) {
00793          trans->thread = 0;
00794          ast_log(LOG_WARNING, "Unable to create thread!\n");
00795          free(st);
00796          memset(&ied, 0, sizeof(ied));
00797          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00798          dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00799          pthread_attr_destroy(&attr);
00800          return -1;
00801       }
00802       pthread_attr_destroy(&attr);
00803    } else {
00804       ast_log(LOG_WARNING, "Out of memory!\n");
00805       memset(&ied, 0, sizeof(ied));
00806       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
00807       dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00808       return -1;
00809    }
00810    return 0;
00811 }

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

Definition at line 1041 of file pbx_dundi.c.

References ast_calloc, ast_copy_string(), AST_LIST_TRAVERSE, ast_log(), ast_pthread_create, dundi_query_state::called_context, dundi_query_state::called_number, dundi_mapping::dcontext, dundi_query_state::directs, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_DPRESPONSE, dundi_eid_cmp(), dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_lookup_thread(), dundi_send(), dundi_query_state::eids, dundi_query_state::fluffy, free, ies, dundi_mapping::list, permission::list, LOG_DEBUG, 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, and dundi_query_state::ttl.

Referenced by handle_command_response().

01042 {
01043    struct dundi_query_state *st;
01044    int totallen;
01045    int x;
01046    struct dundi_ie_data ied;
01047    char *s;
01048    struct dundi_mapping *cur;
01049    int mapcount = 0;
01050    int skipfirst = 0;
01051    
01052    pthread_t lookupthread;
01053    pthread_attr_t attr;
01054    totallen = sizeof(struct dundi_query_state);
01055    /* Count matching map entries */
01056    AST_LIST_TRAVERSE(&mappings, cur, list) {
01057       if (!strcasecmp(cur->dcontext, ccontext))
01058          mapcount++;
01059    }
01060    /* If no maps, return -1 immediately */
01061    if (!mapcount)
01062       return -1;
01063 
01064    if (ies->eidcount > 1) {
01065       /* Since it is a requirement that the first EID is the authenticating host
01066          and the last EID is the root, it is permissible that the first and last EID
01067          could be the same.  In that case, we should go ahead copy only the "root" section
01068          since we will not need it for authentication. */
01069       if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
01070          skipfirst = 1;
01071    }
01072 
01073    totallen += mapcount * sizeof(struct dundi_mapping);
01074    totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
01075    st = ast_calloc(1, totallen);
01076    if (st) {
01077       ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
01078       ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
01079       st->trans = trans;
01080       st->ttl = ies->ttl - 1;
01081       st->nocache = ies->cbypass;
01082       if (st->ttl < 0)
01083          st->ttl = 0;
01084       s = st->fluffy;
01085       for (x=skipfirst;ies->eids[x];x++) {
01086          st->eids[x-skipfirst] = (dundi_eid *)s;
01087          *st->eids[x-skipfirst] = *ies->eids[x];
01088          st->directs[x-skipfirst] = ies->eid_direct[x];
01089          s += sizeof(dundi_eid);
01090       }
01091       /* Append mappings */
01092       x = 0;
01093       st->maps = (struct dundi_mapping *)s;
01094       AST_LIST_TRAVERSE(&mappings, cur, list) {
01095          if (!strcasecmp(cur->dcontext, ccontext)) {
01096             if (x < mapcount) {
01097                st->maps[x] = *cur;
01098                st->maps[x].list.next = NULL;
01099                x++;
01100             }
01101          }
01102       }
01103       st->nummaps = mapcount;
01104       ast_log(LOG_DEBUG, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
01105       pthread_attr_init(&attr);
01106       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01107       trans->thread = 1;
01108       if (ast_pthread_create(&lookupthread, &attr, dundi_lookup_thread, st)) {
01109          trans->thread = 0;
01110          ast_log(LOG_WARNING, "Unable to create thread!\n");
01111          free(st);
01112          memset(&ied, 0, sizeof(ied));
01113          dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
01114          dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01115          pthread_attr_destroy(&attr);
01116          return -1;
01117       }
01118       pthread_attr_destroy(&attr);
01119    } else {
01120       ast_log(LOG_WARNING, "Out of memory!\n");
01121       memset(&ied, 0, sizeof(ied));
01122       dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
01123       dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
01124       return -1;
01125    }
01126    return 0;
01127 }

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04351 {
04352    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04353 }

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

Definition at line 280 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

00281 {
00282    if (dundidebug)
00283       ast_verbose("%s", data);
00284 }

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

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

01362 {
01363    int space = *dstlen;
01364    unsigned long bytes;
01365    struct dundi_hdr *h;
01366    unsigned char *decrypt_space;
01367    decrypt_space = alloca(srclen);
01368    if (!decrypt_space)
01369       return NULL;
01370    decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
01371    /* Setup header */
01372    h = (struct dundi_hdr *)dst;
01373    *h = *ohdr;
01374    bytes = space - 6;
01375    if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
01376       ast_log(LOG_DEBUG, "Ouch, uncompress failed :(\n");
01377       return NULL;
01378    }
01379    /* Update length */
01380    *dstlen = bytes + 6;
01381    /* Return new header */
01382    return h;
01383 }

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

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

static int dundi_do_debug ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2256 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02257 {
02258    if (argc != 2)
02259       return RESULT_SHOWUSAGE;
02260    dundidebug = 1;
02261    ast_cli(fd, "DUNDi Debugging Enabled\n");
02262    return RESULT_SUCCESS;
02263 }

static int dundi_do_lookup ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2383 of file pbx_dundi.c.

References ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), dr, dundi_flags2str(), dundi_lookup(), MAX_RESULTS, RESULT_SHOWUSAGE, RESULT_SUCCESS, and sort_results().

02384 {
02385    int res;
02386    char tmp[256];
02387    char fs[80] = "";
02388    char *context;
02389    int x;
02390    int bypass = 0;
02391    struct dundi_result dr[MAX_RESULTS];
02392    struct timeval start;
02393    if ((argc < 3) || (argc > 4))
02394       return RESULT_SHOWUSAGE;
02395    if (argc > 3) {
02396       if (!strcasecmp(argv[3], "bypass"))
02397          bypass=1;
02398       else
02399          return RESULT_SHOWUSAGE;
02400    }
02401    ast_copy_string(tmp, argv[2], sizeof(tmp));
02402    context = strchr(tmp, '@');
02403    if (context) {
02404       *context = '\0';
02405       context++;
02406    }
02407    start = ast_tvnow();
02408    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02409    
02410    if (res < 0) 
02411       ast_cli(fd, "DUNDi lookup returned error.\n");
02412    else if (!res) 
02413       ast_cli(fd, "DUNDi lookup returned no results.\n");
02414    else
02415       sort_results(dr, res);
02416    for (x=0;x<res;x++) {
02417       ast_cli(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));
02418       ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02419    }
02420    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02421    return RESULT_SUCCESS;
02422 }

static int dundi_do_precache ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2424 of file pbx_dundi.c.

References ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), dundi_precache(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02425 {
02426    int res;
02427    char tmp[256];
02428    char *context;
02429    struct timeval start;
02430    if ((argc < 3) || (argc > 3))
02431       return RESULT_SHOWUSAGE;
02432    ast_copy_string(tmp, argv[2], sizeof(tmp));
02433    context = strchr(tmp, '@');
02434    if (context) {
02435       *context = '\0';
02436       context++;
02437    }
02438    start = ast_tvnow();
02439    res = dundi_precache(context, tmp);
02440    
02441    if (res < 0) 
02442       ast_cli(fd, "DUNDi precache returned error.\n");
02443    else if (!res) 
02444       ast_cli(fd, "DUNDi precache returned no error.\n");
02445    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02446    return RESULT_SUCCESS;
02447 }

static int dundi_do_query ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2449 of file pbx_dundi.c.

References ast_cli(), ast_copy_string(), dundi_entity_info::country, dundi_query_eid(), dundi_str_to_eid(), dundi_entity_info::email, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_entity_info::stateprov.

02450 {
02451    int res;
02452    char tmp[256];
02453    char *context;
02454    dundi_eid eid;
02455    struct dundi_entity_info dei;
02456    if ((argc < 3) || (argc > 3))
02457       return RESULT_SHOWUSAGE;
02458    if (dundi_str_to_eid(&eid, argv[2])) {
02459       ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
02460       return RESULT_SHOWUSAGE;
02461    }
02462    ast_copy_string(tmp, argv[2], sizeof(tmp));
02463    context = strchr(tmp, '@');
02464    if (context) {
02465       *context = '\0';
02466       context++;
02467    }
02468    res = dundi_query_eid(&dei, context, eid);
02469    if (res < 0) 
02470       ast_cli(fd, "DUNDi Query EID returned error.\n");
02471    else if (!res) 
02472       ast_cli(fd, "DUNDi Query EID returned no results.\n");
02473    else {
02474       ast_cli(fd, "DUNDi Query EID succeeded:\n");
02475       ast_cli(fd, "Department:      %s\n", dei.orgunit);
02476       ast_cli(fd, "Organization:    %s\n", dei.org);
02477       ast_cli(fd, "City/Locality:   %s\n", dei.locality);
02478       ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
02479       ast_cli(fd, "Country:         %s\n", dei.country);
02480       ast_cli(fd, "E-mail:          %s\n", dei.email);
02481       ast_cli(fd, "Phone:           %s\n", dei.phone);
02482       ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
02483    }
02484    return RESULT_SUCCESS;
02485 }

static int dundi_do_store_history ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2265 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02266 {
02267    if (argc != 3)
02268       return RESULT_SHOWUSAGE;
02269    global_storehistory = 1;
02270    ast_cli(fd, "DUNDi History Storage Enabled\n");
02271    return RESULT_SUCCESS;
02272 }

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

Definition at line 1385 of file pbx_dundi.c.

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

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

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

Definition at line 286 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00287 {
00288    ast_log(LOG_WARNING, "%s", data);
00289 }

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

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

04356 {
04357    struct dundi_result results[MAX_RESULTS];
04358    int res;
04359    int x=0;
04360    char req[1024];
04361    struct ast_app *dial;
04362    
04363    if (!strncasecmp(context, "macro-", 6)) {
04364       if (!chan) {   
04365          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04366          return -1;
04367       }
04368       /* If done as a macro, use macro extension */
04369       if (!strcasecmp(exten, "s")) {
04370          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04371          if (ast_strlen_zero(exten))
04372             exten = chan->macroexten;
04373          if (ast_strlen_zero(exten))
04374             exten = chan->exten;
04375          if (ast_strlen_zero(exten)) { 
04376             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04377             return -1;
04378          }
04379       }
04380       if (ast_strlen_zero(data))
04381          data = "e164";
04382    } else {
04383       if (ast_strlen_zero(data))
04384          data = context;
04385    }
04386    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04387    if (res > 0) {
04388       sort_results(results, res);
04389       for (x=0;x<res;x++) {
04390          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04391             if (!--priority)
04392                break;
04393          }
04394       }
04395    }
04396    if (x < res) {
04397       /* Got a hit! */
04398       snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
04399       dial = pbx_findapp("Dial");
04400       if (dial)
04401          res = pbx_exec(chan, dial, req);
04402    } else
04403       res = -1;
04404    return res;
04405 }

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04346 {
04347    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04348 }

static int dundi_flush ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2274 of file pbx_dundi.c.

References ast_cli(), ast_db_deltree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, DUNDI_TIMING_HISTORY, free, dundi_peer::list, dundi_peer::lookups, dundi_peer::lookuptimes, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02275 {
02276    int stats = 0;
02277    if ((argc < 2) || (argc > 3))
02278       return RESULT_SHOWUSAGE;
02279    if (argc > 2) {
02280       if (!strcasecmp(argv[2], "stats"))
02281          stats = 1;
02282       else
02283          return RESULT_SHOWUSAGE;
02284    }
02285    if (stats) {
02286       /* Flush statistics */
02287       struct dundi_peer *p;
02288       int x;
02289       AST_LIST_LOCK(&peers);
02290       AST_LIST_TRAVERSE(&peers, p, list) {
02291          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02292             if (p->lookups[x])
02293                free(p->lookups[x]);
02294             p->lookups[x] = NULL;
02295             p->lookuptimes[x] = 0;
02296          }
02297          p->avgms = 0;
02298       }
02299       AST_LIST_UNLOCK(&peers);
02300    } else {
02301       ast_db_deltree("dundi/cache", NULL);
02302       ast_cli(fd, "DUNDi Cache Flushed\n");
02303    }
02304    return RESULT_SUCCESS;
02305 }

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

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

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

04307 {
04308    struct dundi_result results[MAX_RESULTS];
04309    int res;
04310    int x;
04311    int found = 0;
04312    if (!strncasecmp(context, "macro-", 6)) {
04313       if (!chan) {   
04314          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04315          return -1;
04316       }
04317       /* If done as a macro, use macro extension */
04318       if (!strcasecmp(exten, "s")) {
04319          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04320          if (ast_strlen_zero(exten))
04321             exten = chan->macroexten;
04322          if (ast_strlen_zero(exten))
04323             exten = chan->exten;
04324          if (ast_strlen_zero(exten)) { 
04325             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04326             return -1;
04327          }
04328       }
04329       if (ast_strlen_zero(data))
04330          data = "e164";
04331    } else {
04332       if (ast_strlen_zero(data))
04333          data = context;
04334    }
04335    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04336    for (x=0;x<res;x++) {
04337       if (ast_test_flag(results + x, flag))
04338          found++;
04339    }
04340    if (found >= priority)
04341       return 1;
04342    return 0;
04343 }

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

Definition at line 3113 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_eid_cmp(), 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().

03114 {
03115    struct dundi_peer *p;
03116    if (!dundi_eid_cmp(eid, us)) {
03117       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03118       return;
03119    }
03120    AST_LIST_LOCK(&peers);
03121    AST_LIST_TRAVERSE(&peers, p, list) {
03122       if (!dundi_eid_cmp(&p->eid, eid)) {
03123          if (has_permission(&p->include, context))
03124             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03125          else
03126             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03127          break;
03128       }
03129    }
03130    if (!p)
03131       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03132    AST_LIST_UNLOCK(&peers);
03133 }

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 (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified. returns the number of results found or -1 on a hangup of teh channel.

Definition at line 3643 of file pbx_dundi.c.

References DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, and dundi_lookup_internal().

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

03644 {
03645    struct dundi_hint_metadata hmd;
03646    dundi_eid *avoid[1] = { NULL, };
03647    int direct[1] = { 0, };
03648    int expiration = dundi_cache_time;
03649    memset(&hmd, 0, sizeof(hmd));
03650    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03651    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03652 }

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

References ast_channel::_softhangup, abort_request(), ast_copy_string(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), check_request(), discover_transactions(), dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, LOG_DEBUG, 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().

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

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

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), 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_eid_to_str(), 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, map, pbx_substitute_variables_varshead(), and tech2str().

Referenced by dundi_lookup_thread(), and precache_trans().

00530 {
00531    struct ast_flags flags = {0};
00532    int x;
00533    if (!ast_strlen_zero(map->lcontext)) {
00534       if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00535          ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00536       if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00537          ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00538       if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00539          ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00540       if (ast_ignore_pattern(map->lcontext, called_number))
00541          ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00542 
00543       /* Clearly we can't say 'don't ask' anymore if we found anything... */
00544       if (ast_test_flag(&flags, AST_FLAGS_ALL)) 
00545          ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00546 
00547       if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00548          /* Skip partial answers */
00549          ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00550       }
00551       if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00552          struct varshead headp;
00553          struct ast_var_t *newvariable;
00554          ast_set_flag(&flags, map->options & 0xffff);
00555          ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00556          dr[anscnt].techint = map->tech;
00557          dr[anscnt].weight = map->weight;
00558          dr[anscnt].expiration = dundi_cache_time;
00559          ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00560          dr[anscnt].eid = *us_eid;
00561          dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00562          if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00563             AST_LIST_HEAD_INIT_NOLOCK(&headp);
00564             newvariable = ast_var_assign("NUMBER", called_number);
00565             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00566             newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
00567             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00568             newvariable = ast_var_assign("SECRET", cursecret);
00569             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00570             newvariable = ast_var_assign("IPADDR", ipaddr);
00571             AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00572             pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00573             while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00574                ast_var_delete(newvariable);
00575          } else
00576             dr[anscnt].dest[0] = '\0';
00577          anscnt++;
00578       } else {
00579          /* No answers...  Find the fewest number of digits from the
00580             number for which we have no answer. */
00581          char tmp[AST_MAX_EXTENSION + 1] = "";
00582          for (x = 0; x < (sizeof(tmp) - 1); x++) {
00583             tmp[x] = called_number[x];
00584             if (!tmp[x])
00585                break;
00586             if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00587                /* Oops found something we can't match.  If this is longer
00588                   than the running hint, we have to consider it */
00589                if (strlen(tmp) > strlen(hmd->exten)) {
00590                   ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00591                }
00592                break;
00593             }
00594          }
00595       }
00596    }
00597    return anscnt;
00598 }

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

Definition at line 602 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), 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_eid_to_str(), 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, free, LOG_DEBUG, 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().

00603 {
00604    struct dundi_query_state *st = data;
00605    struct dundi_result dr[MAX_RESULTS];
00606    struct dundi_ie_data ied;
00607    struct dundi_hint_metadata hmd;
00608    char eid_str[20];
00609    int res, x;
00610    int ouranswers=0;
00611    int max = 999999;
00612    int expiration = dundi_cache_time;
00613 
00614    ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00615       st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00616    memset(&ied, 0, sizeof(ied));
00617    memset(&dr, 0, sizeof(dr));
00618    memset(&hmd, 0, sizeof(hmd));
00619    /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
00620    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00621    for (x=0;x<st->nummaps;x++)
00622       ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00623    if (ouranswers < 0)
00624       ouranswers = 0;
00625    for (x=0;x<ouranswers;x++) {
00626       if (dr[x].weight < max)
00627          max = dr[x].weight;
00628    }
00629       
00630    if (max) {
00631       /* If we do not have a canonical result, keep looking */
00632       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);
00633       if (res > 0) {
00634          /* Append answer in result */
00635          ouranswers += res;
00636       } else {
00637          if ((res < -1) && (!ouranswers))
00638             dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00639       }
00640    }
00641    AST_LIST_LOCK(&peers);
00642    /* Truncate if "don't ask" isn't present */
00643    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00644       hmd.exten[0] = '\0';
00645    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00646       ast_log(LOG_DEBUG, "Our transaction went away!\n");
00647       st->trans->thread = 0;
00648       destroy_trans(st->trans, 0);
00649    } else {
00650       for (x=0;x<ouranswers;x++) {
00651          /* Add answers */
00652          if (dr[x].expiration && (expiration > dr[x].expiration))
00653             expiration = dr[x].expiration;
00654          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00655       }
00656       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00657       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00658       dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00659       st->trans->thread = 0;
00660    }
00661    AST_LIST_UNLOCK(&peers);
00662    free(st);
00663    return NULL;   
00664 }

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04408 {
04409    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04410 }

static int dundi_no_debug ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2307 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02308 {
02309    if (argc != 3)
02310       return RESULT_SHOWUSAGE;
02311    dundidebug = 0;
02312    ast_cli(fd, "DUNDi Debugging Disabled\n");
02313    return RESULT_SUCCESS;
02314 }

static int dundi_no_store_history ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2316 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02317 {
02318    if (argc != 4)
02319       return RESULT_SHOWUSAGE;
02320    global_storehistory = 0;
02321    ast_cli(fd, "DUNDi History Storage Disabled\n");
02322    return RESULT_SUCCESS;
02323 }

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

Pre-cache to push upstream peers.

Definition at line 3790 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03791 {
03792    dundi_eid *avoid[1] = { NULL, };
03793    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03794 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3690 of file pbx_dundi.c.

References ast_get_context_name(), ast_get_extension_name(), AST_LIST_TRAVERSE, ast_lock_context(), ast_log(), 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().

03691 {
03692    struct dundi_mapping *cur;
03693    struct ast_context *con;
03694    struct ast_exten *e;
03695 
03696    AST_LIST_TRAVERSE(&mappings, cur, list) {
03697       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03698       ast_rdlock_contexts();
03699       con = ast_walk_contexts(NULL);
03700       while (con) {
03701          if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
03702             /* Found the match, now queue them all up */
03703             ast_lock_context(con);
03704             e = ast_walk_context_extensions(con, NULL);
03705             while (e) {
03706                reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03707                e = ast_walk_context_extensions(con, e);
03708             }
03709             ast_unlock_context(con);
03710          }
03711          con = ast_walk_contexts(con);
03712       }
03713       ast_unlock_contexts();
03714    }
03715 }

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

Definition at line 3717 of file pbx_dundi.c.

References ast_copy_string(), 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_DEBUG, LOG_NOTICE, LOG_WARNING, MAX_RESULTS, optimize_transactions(), precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

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

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

Definition at line 666 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_PRECACHERP, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, dundi_precache_internal(), dundi_send(), dundi_query_state::eids, dundi_hint_metadata::exten, FLAG_DEAD, free, LOG_DEBUG, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

00667 {
00668    struct dundi_query_state *st = data;
00669    struct dundi_ie_data ied;
00670    struct dundi_hint_metadata hmd;
00671    char eid_str[20];
00672 
00673    ast_log(LOG_DEBUG, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00674       st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00675    memset(&ied, 0, sizeof(ied));
00676 
00677    /* Now produce precache */
00678    dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00679 
00680    AST_LIST_LOCK(&peers);
00681    /* Truncate if "don't ask" isn't present */
00682    if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00683       hmd.exten[0] = '\0';
00684    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00685       ast_log(LOG_DEBUG, "Our transaction went away!\n");
00686       st->trans->thread = 0;
00687       destroy_trans(st->trans, 0);
00688    } else {
00689       dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00690       st->trans->thread = 0;
00691    }
00692    AST_LIST_UNLOCK(&peers);
00693    free(st);
00694    return NULL;   
00695 }

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

Definition at line 889 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_string(), dundi_result::dest, dundi_request::dr, dr, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_request::hmd, ies, MAX_RESULTS, dundi_request::maxcount, dundi_transaction::parent, dundi_request::respcount, s, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

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

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

Retrieve information on a specific EID.

Definition at line 3843 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03844 {
03845    dundi_eid *avoid[1] = { NULL, };
03846    struct dundi_hint_metadata hmd;
03847    memset(&hmd, 0, sizeof(hmd));
03848    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03849 }

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

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

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

Definition at line 699 of file pbx_dundi.c.

References ast_copy_string(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), 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, free, LOG_DEBUG, 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().

00700 {
00701    struct dundi_query_state *st = data;
00702    struct dundi_entity_info dei;
00703    struct dundi_ie_data ied;
00704    struct dundi_hint_metadata hmd;
00705    char eid_str[20];
00706    int res;
00707    ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 
00708       st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) :  "ourselves");
00709    memset(&ied, 0, sizeof(ied));
00710    memset(&dei, 0, sizeof(dei));
00711    memset(&hmd, 0, sizeof(hmd));
00712    if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00713       /* Ooh, it's us! */
00714       ast_log(LOG_DEBUG, "Neat, someone look for us!\n");
00715       ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00716       ast_copy_string(dei.org, org, sizeof(dei.org));
00717       ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00718       ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00719       ast_copy_string(dei.country, country, sizeof(dei.country));
00720       ast_copy_string(dei.email, email, sizeof(dei.email));
00721       ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00722       res = 1;
00723    } else {
00724       /* If we do not have a canonical result, keep looking */
00725       res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00726    }
00727    AST_LIST_LOCK(&peers);
00728    if (ast_test_flag(st->trans, FLAG_DEAD)) {
00729       ast_log(LOG_DEBUG, "Our transaction went away!\n");
00730       st->trans->thread = 0;
00731       destroy_trans(st->trans, 0);
00732    } else {
00733       if (res) {
00734          dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00735          dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00736          dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00737          dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00738          dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00739          dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00740          dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00741          if (!ast_strlen_zero(dei.ipaddr))
00742             dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00743       }
00744       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00745       dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00746       st->trans->thread = 0;
00747    }
00748    AST_LIST_UNLOCK(&peers);
00749    free(st);
00750    return NULL;   
00751 }

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

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

00381 {
00382    struct {
00383       struct dundi_packet pack;
00384       struct dundi_hdr hdr;
00385    } tmp;
00386    struct dundi_transaction trans;
00387    /* Never respond to an INVALID with another INVALID */
00388    if (h->cmdresp == DUNDI_COMMAND_INVALID)
00389       return;
00390    memset(&tmp, 0, sizeof(tmp));
00391    memset(&trans, 0, sizeof(trans));
00392    memcpy(&trans.addr, sin, sizeof(trans.addr));
00393    tmp.hdr.strans = h->dtrans;
00394    tmp.hdr.dtrans = h->strans;
00395    tmp.hdr.iseqno = h->oseqno;
00396    tmp.hdr.oseqno = h->iseqno;
00397    tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00398    tmp.hdr.cmdflags = 0;
00399    tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00400    tmp.pack.datalen = sizeof(struct dundi_hdr);
00401    tmp.pack.parent = &trans;
00402    dundi_xmit(&tmp.pack);
00403 }

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

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

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

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

Definition at line 3031 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, 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_eid_to_str(), dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, free, 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().

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

static int dundi_show_entityid ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2655 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_UNLOCK, dundi_eid_to_str(), global_eid, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02656 {
02657    char eid_str[20];
02658    if (argc != 3)
02659       return RESULT_SHOWUSAGE;
02660    AST_LIST_LOCK(&peers);
02661    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02662    AST_LIST_UNLOCK(&peers);
02663    ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
02664    return RESULT_SUCCESS;
02665 }

static int dundi_show_mappings ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2689 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), dundi_flags2str(), FORMAT, FORMAT2, dundi_mapping::list, map, RESULT_SHOWUSAGE, RESULT_SUCCESS, and tech2str().

02690 {
02691 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02692 #define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
02693    struct dundi_mapping *map;
02694    char fs[256];
02695    if (argc != 3)
02696       return RESULT_SHOWUSAGE;
02697    AST_LIST_LOCK(&peers);
02698    ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02699    AST_LIST_TRAVERSE(&mappings, map, list) {
02700       ast_cli(fd, FORMAT, map->dcontext, map->weight, 
02701          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02702          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02703    }
02704    AST_LIST_UNLOCK(&peers);
02705    return RESULT_SUCCESS;
02706 #undef FORMAT
02707 #undef FORMAT2
02708 }

static int dundi_show_peer ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2487 of file pbx_dundi.c.

References dundi_peer::addr, permission::allow, ast_cli(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_strlen_zero(), dundi_peer::avgms, dundi_eid_to_str(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::dynamic, dundi_peer::eid, dundi_peer::include, dundi_peer::inkey, permission::list, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::model, model2str(), permission::name, dundi_peer::order, dundi_peer::outkey, dundi_peer::permit, dundi_peer::registerid, and RESULT_SHOWUSAGE.

02488 {
02489    struct dundi_peer *peer;
02490    struct permission *p;
02491    char *order;
02492    char eid_str[20];
02493    int x, cnt;
02494    
02495    if (argc != 4)
02496       return RESULT_SHOWUSAGE;
02497    AST_LIST_LOCK(&peers);
02498    AST_LIST_TRAVERSE(&peers, peer, list) {
02499       if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), argv[3]))
02500          break;
02501    }
02502    if (peer) {
02503       switch(peer->order) {
02504       case 0:
02505          order = "Primary";
02506          break;
02507       case 1:
02508          order = "Secondary";
02509          break;
02510       case 2:
02511          order = "Tertiary";
02512          break;
02513       case 3:
02514          order = "Quartiary";
02515          break;
02516       default:
02517          order = "Unknown";
02518       }
02519       ast_cli(fd, "Peer:    %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02520       ast_cli(fd, "Model:   %s\n", model2str(peer->model));
02521       ast_cli(fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02522       ast_cli(fd, "Port:    %d\n", ntohs(peer->addr.sin_port));
02523       ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02524       ast_cli(fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02525       ast_cli(fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02526       ast_cli(fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02527       if (!AST_LIST_EMPTY(&peer->include))
02528          ast_cli(fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02529       AST_LIST_TRAVERSE(&peer->include, p, list)
02530          ast_cli(fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02531       if (!AST_LIST_EMPTY(&peer->permit))
02532          ast_cli(fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02533       AST_LIST_TRAVERSE(&peer->permit, p, list)
02534          ast_cli(fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02535       cnt = 0;
02536       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02537          if (peer->lookups[x]) {
02538             if (!cnt)
02539                ast_cli(fd, "Last few query times:\n");
02540             ast_cli(fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02541             cnt++;
02542          }
02543       }
02544       if (cnt)
02545          ast_cli(fd, "Average query time: %d ms\n", peer->avgms);
02546    } else
02547       ast_cli(fd, "No such peer '%s'\n", argv[3]);
02548    AST_LIST_UNLOCK(&peers);
02549    return RESULT_SUCCESS;
02550 }

static int dundi_show_peers ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2552 of file pbx_dundi.c.

References dundi_peer::addr, ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, dundi_eid_to_str(), dundi_peer::dynamic, dundi_peer::eid, FORMAT, FORMAT2, dundi_peer::lastms, dundi_peer::list, dundi_peer::maxms, dundi_peer::model, model2str(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02553 {
02554 #define FORMAT2 "%-20.20s %-15.15s     %-6.6s %-10.10s %-8.8s %-15.15s\n"
02555 #define FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n"
02556    struct dundi_peer *peer;
02557    int registeredonly=0;
02558    char avgms[20];
02559    char eid_str[20];
02560    int online_peers = 0;
02561    int offline_peers = 0;
02562    int unmonitored_peers = 0;
02563    int total_peers = 0;
02564 
02565    if ((argc != 3) && (argc != 4) && (argc != 5))
02566       return RESULT_SHOWUSAGE;
02567    if ((argc == 4)) {
02568       if (!strcasecmp(argv[3], "registered")) {
02569          registeredonly = 1;
02570       } else
02571          return RESULT_SHOWUSAGE;
02572    }
02573    AST_LIST_LOCK(&peers);
02574    ast_cli(fd, FORMAT2, "EID", "Host", "Port", "Model", "AvgTime", "Status");
02575    AST_LIST_TRAVERSE(&peers, peer, list) {
02576       char status[20];
02577       int print_line = -1;
02578       char srch[2000];
02579       total_peers++;
02580       if (registeredonly && !peer->addr.sin_addr.s_addr)
02581          continue;
02582       if (peer->maxms) {
02583          if (peer->lastms < 0) {
02584             strcpy(status, "UNREACHABLE");
02585             offline_peers++;
02586          }
02587          else if (peer->lastms > peer->maxms) {
02588             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02589             offline_peers++;
02590          }
02591          else if (peer->lastms) {
02592             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02593             online_peers++;
02594          }
02595          else {
02596             strcpy(status, "UNKNOWN");
02597             offline_peers++;
02598          }
02599       } else {
02600          strcpy(status, "Unmonitored");
02601          unmonitored_peers++;
02602       }
02603       if (peer->avgms) 
02604          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02605       else
02606          strcpy(avgms, "Unavail");
02607       snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02608                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02609                peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);
02610 
02611                 if (argc == 5) {
02612                   if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) {
02613                         print_line = -1;
02614                    } else if (!strcasecmp(argv[3],"exclude") && !strstr(srch,argv[4])) {
02615                         print_line = 1;
02616                    } else if (!strcasecmp(argv[3],"begin") && !strncasecmp(srch,argv[4],strlen(argv[4]))) {
02617                         print_line = -1;
02618                    } else {
02619                         print_line = 0;
02620                   }
02621                 }
02622       
02623         if (print_line) {
02624          ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02625                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02626                peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);
02627       }
02628    }
02629    ast_cli(fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02630    AST_LIST_UNLOCK(&peers);
02631    return RESULT_SUCCESS;
02632 #undef FORMAT
02633 #undef FORMAT2
02634 }

static int dundi_show_precache ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2710 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_precache_queue::context, dundi_precache_queue::expiration, FORMAT, FORMAT2, dundi_precache_queue::list, dundi_precache_queue::number, RESULT_SHOWUSAGE, RESULT_SUCCESS, and s.

02711 {
02712 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02713 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02714    struct dundi_precache_queue *qe;
02715    int h,m,s;
02716    time_t now;
02717    
02718    if (argc != 3)
02719       return RESULT_SHOWUSAGE;
02720    time(&now);
02721    ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
02722    AST_LIST_LOCK(&pcq);
02723    AST_LIST_TRAVERSE(&pcq, qe, list) {
02724       s = qe->expiration - now;
02725       h = s / 3600;
02726       s = s % 3600;
02727       m = s / 60;
02728       s = s % 60;
02729       ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
02730    }
02731    AST_LIST_UNLOCK(&pcq);
02732    
02733    return RESULT_SUCCESS;
02734 #undef FORMAT
02735 #undef FORMAT2
02736 }

static int dundi_show_requests ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2667 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::dcontext, dundi_eid_to_str(), dundi_eid_zero(), FORMAT, FORMAT2, dundi_request::list, dundi_request::maxcount, dundi_request::number, dundi_request::respcount, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_request::root_eid.

02668 {
02669 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02670 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02671    struct dundi_request *req;
02672    char eidstr[20];
02673    if (argc != 3)
02674       return RESULT_SHOWUSAGE;
02675    AST_LIST_LOCK(&peers);
02676    ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02677    AST_LIST_TRAVERSE(&requests, req, list) {
02678       ast_cli(fd, FORMAT, req->number, req->dcontext,
02679          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02680    }
02681    AST_LIST_UNLOCK(&peers);
02682    return RESULT_SUCCESS;
02683 #undef FORMAT
02684 #undef FORMAT2
02685 }

static int dundi_show_trans ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 2636 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::all, dundi_transaction::aseqno, ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_transaction::dtrans, FORMAT, FORMAT2, dundi_transaction::iseqno, dundi_transaction::oseqno, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_transaction::strans.

02637 {
02638 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02639 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02640    struct dundi_transaction *trans;
02641    if (argc != 3)
02642       return RESULT_SHOWUSAGE;
02643    AST_LIST_LOCK(&peers);
02644    ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02645    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02646       ast_cli(fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02647          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02648    }
02649    AST_LIST_UNLOCK(&peers);
02650    return RESULT_SUCCESS;
02651 #undef FORMAT
02652 #undef FORMAT2
02653 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02901 {
02902    int res;
02903    if (dundidebug)
02904       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02905    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02906    if (res < 0) {
02907       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02908          ast_inet_ntoa(pack->parent->addr.sin_addr),
02909          ntohs(pack->parent->addr.sin_port), strerror(errno));
02910    }
02911    if (res > 0)
02912       res = 0;
02913    return res;
02914 }

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

Definition at line 3851 of file pbx_dundi.c.

References ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), ast_test_flag, dundi_result::dest, dr, DUNDI_FLAG_EXISTS, dundi_lookup(), LOG_WARNING, MAX_RESULTS, sort_results(), and dundi_result::tech.

03852 {
03853    char *context;
03854    char *opts;
03855    int results;
03856    int x;
03857    int bypass = 0;
03858    struct ast_module_user *u;
03859    struct dundi_result dr[MAX_RESULTS];
03860 
03861    buf[0] = '\0';
03862 
03863    if (ast_strlen_zero(num)) {
03864       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03865       return -1;
03866    }
03867 
03868    u = ast_module_user_add(chan);
03869 
03870    context = strchr(num, '|');
03871    if (context) {
03872       *context++ = '\0';
03873       opts = strchr(context, '|');
03874       if (opts) {
03875          *opts++ = '\0';
03876          if (strchr(opts, 'b'))
03877             bypass = 1;
03878       }
03879    }
03880 
03881    if (ast_strlen_zero(context))
03882       context = "e164";
03883    
03884    results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
03885    if (results > 0) {
03886       sort_results(dr, results);
03887       for (x = 0; x < results; x++) {
03888          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03889             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03890             break;
03891          }
03892       }
03893    }
03894 
03895    ast_module_user_remove(u);
03896 
03897    return 0;
03898 }

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

Definition at line 1328 of file pbx_dundi.c.

References aes_encrypt().

Referenced by dundi_encrypt().

01329 {
01330    unsigned char curblock[16];
01331    int x;
01332    memcpy(curblock, iv, sizeof(curblock));
01333    while(len > 0) {
01334       for (x=0;x<16;x++)
01335          curblock[x] ^= src[x];
01336       aes_encrypt(curblock, dst, ecx);
01337       memcpy(curblock, dst, sizeof(curblock)); 
01338       dst += 16;
01339       src += 16;
01340       len -= 16;
01341    }
01342    return 0;
01343 }

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

Definition at line 485 of file pbx_dundi.c.

References any_peer, AST_LIST_TRAVERSE, dundi_eid_cmp(), dundi_peer::eid, and empty_eid.

00486 {
00487    struct dundi_peer *cur = NULL;
00488 
00489    if (!eid)
00490       eid = &empty_eid;
00491    
00492    AST_LIST_TRAVERSE(&peers, cur, list) {
00493       if (!dundi_eid_cmp(&cur->eid,eid))
00494          break;
00495    }
00496 
00497    if (!cur && any_peer)
00498       cur = any_peer;
00499 
00500    return cur;
00501 }

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

Definition at line 335 of file pbx_dundi.c.

References dundi_transaction::addr, AST_LIST_TRAVERSE, ast_log(), 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(), LOG_WARNING, dundi_hdr::strans, and dundi_transaction::strans.

Referenced by handle_frame().

00336 {
00337    struct dundi_transaction *trans;
00338 
00339    /* Look for an exact match first */
00340    AST_LIST_TRAVERSE(&alltrans, trans, all) {
00341       if (!inaddrcmp(&trans->addr, sin) && 
00342            ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
00343            ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
00344            if (hdr->strans)
00345               trans->dtrans = ntohs(hdr->strans) & 32767;
00346            break;
00347       }
00348    }
00349    if (!trans) {
00350       switch(hdr->cmdresp & 0x7f) {
00351       case DUNDI_COMMAND_DPDISCOVER:
00352       case DUNDI_COMMAND_EIDQUERY:
00353       case DUNDI_COMMAND_PRECACHERQ:
00354       case DUNDI_COMMAND_REGREQ:
00355       case DUNDI_COMMAND_NULL:
00356       case DUNDI_COMMAND_ENCRYPT:
00357          if (hdr->strans) {   
00358             /* Create new transaction */
00359             trans = create_transaction(NULL);
00360             if (trans) {
00361                memcpy(&trans->addr, sin, sizeof(trans->addr));
00362                trans->dtrans = ntohs(hdr->strans) & 32767;
00363             } else
00364                ast_log(LOG_WARNING, "Out of memory!\n");
00365          }
00366          break;
00367       default:
00368          break;
00369       }
00370    }
00371    return trans;
00372 }

static int get_trans_id ( void   )  [static]

Definition at line 450 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_random(), and t.

Referenced by create_transaction(), and reset_transaction().

00451 {
00452    struct dundi_transaction *t;
00453    int stid = (ast_random() % 32766) + 1;
00454    int tid = stid;
00455 
00456    do {
00457       AST_LIST_TRAVERSE(&alltrans, t, all) {
00458          if (t->strans == tid) 
00459             break;
00460       }
00461       if (!t)
00462          return tid;
00463       tid = (tid % 32766) + 1;
00464    } while (tid != stid);
00465 
00466    return 0;
00467 }

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

Definition at line 1536 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, any_peer, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), 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_verbose(), cache_save(), cache_save_hint(), dundi_hdr::cmdresp, 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(), 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_peer::eid, dundi_request::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, has_permission(), dundi_request::hmd, dundi_hdr::ies, ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, permission::list, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_peer::model, dundi_request::number, option_verbose, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_ie_data::pos, 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, VERBOSE_PREFIX_3, and dundi_result::weight.

Referenced by handle_frame().

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

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

Definition at line 1997 of file pbx_dundi.c.

References ack_trans(), dundi_transaction::aseqno, ast_log(), 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, LOG_DEBUG, dundi_transaction::oiseqno, and dundi_hdr::oseqno.

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

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

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

00292 {
00293    struct permission *perm;
00294    int res = 0;
00295 
00296    AST_LIST_TRAVERSE(permlist, perm, list) {
00297       if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
00298          res = perm->allow;
00299    }
00300 
00301    return res;
00302 }

static int load_module ( void   )  [static]

Definition at line 4622 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_register_switch(), ast_verbose(), cli_dundi, dundi_debug_output(), dundi_error_output(), dundi_function, DUNDI_PORT, dundi_set_error(), dundi_set_output(), dundi_switch, errno, io, io_context_create(), LOG_ERROR, option_verbose, sched, sched_context_create(), set_config(), start_network_thread(), and VERBOSE_PREFIX_2.

04623 {
04624    int res = 0;
04625    struct sockaddr_in sin;
04626 
04627    dundi_set_output(dundi_debug_output);
04628    dundi_set_error(dundi_error_output);
04629    
04630    sin.sin_family = AF_INET;
04631    sin.sin_port = ntohs(DUNDI_PORT);
04632    sin.sin_addr.s_addr = INADDR_ANY;
04633 
04634    /* Make a UDP socket */
04635    io = io_context_create();
04636    sched = sched_context_create();
04637    
04638    if (!io || !sched) {
04639       ast_log(LOG_ERROR, "Out of memory\n");
04640       return AST_MODULE_LOAD_DECLINE;
04641    }
04642 
04643    if(set_config("dundi.conf",&sin))
04644       return AST_MODULE_LOAD_DECLINE;
04645 
04646    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04647    
04648    if (netsocket < 0) {
04649       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04650       return AST_MODULE_LOAD_DECLINE;
04651    }
04652    if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
04653       ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
04654       return AST_MODULE_LOAD_DECLINE;
04655    }
04656 
04657    if (option_verbose > 1)
04658       ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
04659 
04660    if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
04661       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
04662    
04663    res = start_network_thread();
04664    if (res) {
04665       ast_log(LOG_ERROR, "Unable to start network thread\n");
04666       close(netsocket);
04667       return AST_MODULE_LOAD_DECLINE;
04668    }
04669 
04670    if (option_verbose > 1)
04671       ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04672 
04673    ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04674    if (ast_register_switch(&dundi_switch))
04675       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04676    ast_custom_function_register(&dundi_function); 
04677    
04678    return AST_MODULE_LOAD_SUCCESS;
04679 }

static void load_password ( void   )  [static]

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

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

static void mark_mappings ( void   )  [static]

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

03928 {
03929    struct dundi_mapping *map;
03930    
03931    AST_LIST_LOCK(&peers);
03932    AST_LIST_TRAVERSE(&mappings, map, list) {
03933       map->dead = 1;
03934    }
03935    AST_LIST_UNLOCK(&peers);
03936 }

static void mark_peers ( void   )  [static]

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

03918 {
03919    struct dundi_peer *peer;
03920    AST_LIST_LOCK(&peers);
03921    AST_LIST_TRAVERSE(&peers, peer, list) {
03922       peer->dead = 1;
03923    }
03924    AST_LIST_UNLOCK(&peers);
03925 }

static char* model2str ( int  model  )  [static]

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

02326 {
02327    switch(model) {
02328    case DUNDI_MODEL_INBOUND:
02329       return "Inbound";
02330    case DUNDI_MODEL_OUTBOUND:
02331       return "Outbound";
02332    case DUNDI_MODEL_SYMMETRIC:
02333       return "Symmetric";
02334    default:
02335       return "Unknown";
02336    }
02337 }

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

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

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

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

Definition at line 3306 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, dr, dundi_eid_cmp(), 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().

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

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

Definition at line 4134 of file pbx_dundi.c.

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

Referenced by build_peer().

04135 {
04136    char data[256];
04137    char *c;
04138    int port, expire;
04139    char eid_str[20];
04140    dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
04141    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04142       c = strchr(data, ':');
04143       if (c) {
04144          *c = '\0';
04145          c++;
04146          if (sscanf(c, "%5d:%30d", &port, &expire) == 2) {
04147             /* Got it! */
04148             inet_aton(data, &peer->addr.sin_addr);
04149             peer->addr.sin_family = AF_INET;
04150             peer->addr.sin_port = htons(port);
04151             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04152          }
04153       }
04154    }
04155 }

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

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

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

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

Definition at line 3258 of file pbx_dundi.c.

References 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_DEBUG, LOG_WARNING, dundi_transaction::parentlist, precache_trans(), and dundi_transaction::thread.

Referenced by dundi_precache_internal().

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

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

Definition at line 2176 of file pbx_dundi.c.

References ast_db_del(), ast_db_freetree(), ast_db_gettree(), ast_get_time_t(), ast_log(), ast_db_entry::data, expiry, ast_db_entry::key, LOG_DEBUG, ast_db_entry::next, and option_debug.

Referenced by start_network_thread().

02177 {
02178    struct ast_db_entry *db_entry, *db_tree;
02179    int striplen = sizeof("/dundi/cache");
02180    time_t now;
02181    
02182    while (!dundi_shutdown) {
02183       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
02184 
02185       time(&now);
02186 
02187       db_entry = db_tree = ast_db_gettree("dundi/cache", NULL);
02188       for (; db_entry; db_entry = db_entry->next) {
02189          time_t expiry;
02190 
02191          if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) {
02192             if (expiry < now) {
02193                if (option_debug)
02194                   ast_log(LOG_DEBUG, "clearing expired DUNDI cache entry: %s\n", db_entry->key);
02195                ast_db_del("dundi/cache", db_entry->key + striplen);
02196             }
02197          }
02198       }
02199       ast_db_freetree(db_tree);
02200 
02201       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
02202       pthread_testcancel();
02203       sleep(60);
02204       pthread_testcancel();
02205    }
02206    
02207    clearcachethreadid = AST_PTHREADT_NULL;
02208    return NULL;
02209 }

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

Definition at line 2211 of file pbx_dundi.c.

References ast_copy_string(), 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, free, dundi_precache_queue::list, and dundi_precache_queue::number.

Referenced by start_network_thread().

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

static void prune_mappings ( void   )  [static]

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

03978 {
03979    struct dundi_mapping *map;
03980 
03981    AST_LIST_LOCK(&peers);
03982    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
03983       if (map->dead) {
03984          AST_LIST_REMOVE_CURRENT(&mappings, list);
03985          destroy_map(map);
03986       }
03987    }
03988    AST_LIST_TRAVERSE_SAFE_END
03989    AST_LIST_UNLOCK(&peers);
03990 }

static void prune_peers ( void   )  [static]

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

03963 {
03964    struct dundi_peer *peer;
03965 
03966    AST_LIST_LOCK(&peers);
03967    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
03968       if (peer->dead) {
03969          AST_LIST_REMOVE_CURRENT(&peers, list);
03970          destroy_peer(peer);
03971       }
03972    }
03973    AST_LIST_TRAVERSE_SAFE_END
03974    AST_LIST_UNLOCK(&peers);
03975 }

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

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

04112 {
04113    int when;
04114    AST_SCHED_DEL(sched, peer->qualifyid);
04115    if (peer->qualtrans)
04116       destroy_trans(peer->qualtrans, 0);
04117    peer->qualtrans = NULL;
04118    if (peer->maxms > 0) {
04119       when = 60000;
04120       if (peer->lastms < 0)
04121          when = 10000;
04122       if (schedonly)
04123          when = 5000;
04124       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04125       if (!schedonly)
04126          peer->qualtrans = create_transaction(peer);
04127       if (peer->qualtrans) {
04128          peer->qualtx = ast_tvnow();
04129          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04130          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04131       }
04132    }
04133 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3293 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, dundi_query(), and dundi_transaction::parentlist.

Referenced by dundi_query_eid_internal().

03294 {
03295    struct dundi_transaction *trans;
03296 
03297    AST_LIST_LOCK(&peers);
03298    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03299       dundi_query(trans);
03300    }
03301    AST_LIST_UNLOCK(&peers);
03302 
03303    return 0;
03304 }

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

Definition at line 3474 of file pbx_dundi.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), dundi_request::crc32, dundi_request::dcontext, dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_request::list, LOG_DEBUG, dundi_request::number, option_debug, and dundi_request::root_eid.

Referenced by dundi_lookup_internal().

03475 {
03476    struct dundi_request *cur;
03477    int res=0;
03478    char eid_str[20];
03479    AST_LIST_LOCK(&peers);
03480    AST_LIST_TRAVERSE(&requests, cur, list) {
03481       if (option_debug)
03482          ast_log(LOG_DEBUG, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03483             dr->dcontext, dr->number);
03484       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03485           !strcasecmp(cur->number, dr->number) &&
03486           (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03487          ast_log(LOG_DEBUG, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 
03488             cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03489          *pending = cur;
03490          res = 1;
03491          break;
03492       }
03493    }
03494    if (!res) {
03495       ast_log(LOG_DEBUG, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 
03496             dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03497       /* Go ahead and link us in since nobody else is searching for this */
03498       AST_LIST_INSERT_HEAD(&requests, dr, list);
03499       *pending = NULL;
03500    }
03501    AST_LIST_UNLOCK(&peers);
03502    return res;
03503 }

static int reload ( void   )  [static]

Definition at line 4615 of file pbx_dundi.c.

References set_config().

04616 {
04617    struct sockaddr_in sin;
04618    set_config("dundi.conf",&sin);
04619    return 0;
04620 }

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

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

03655 {
03656    int len;
03657    struct dundi_precache_queue *qe, *prev;
03658 
03659    AST_LIST_LOCK(&pcq);
03660    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03661       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03662          AST_LIST_REMOVE_CURRENT(&pcq, list);
03663          break;
03664       }
03665    }
03666    AST_LIST_TRAVERSE_SAFE_END
03667    if (!qe) {
03668       len = sizeof(*qe);
03669       len += strlen(number) + 1;
03670       len += strlen(context) + 1;
03671       if (!(qe = ast_calloc(1, len))) {
03672          AST_LIST_UNLOCK(&pcq);
03673          return;
03674       }
03675       strcpy(qe->number, number);
03676       qe->context = qe->number + strlen(number) + 1;
03677       strcpy(qe->context, context);
03678    }
03679    time(&qe->expiration);
03680    qe->expiration += expiration;
03681    if ((prev = AST_LIST_FIRST(&pcq))) {
03682       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03683          prev = AST_LIST_NEXT(prev, list);
03684       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03685    } else
03686       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03687    AST_LIST_UNLOCK(&pcq);
03688 }

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

Definition at line 2366 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02367 {
02368    const struct dundi_result *resa, *resb;
02369    resa = a;
02370    resb = b;
02371    if (resa->weight < resb->weight)
02372       return -1;
02373    if (resa->weight > resb->weight)
02374       return 1;
02375    return 0;
02376 }

static void reset_global_eid ( void   )  [static]

Definition at line 405 of file pbx_dundi.c.

References ast_log(), dundi_eid_to_str(), _dundi_eid::eid, global_eid, LOG_DEBUG, and s.

Referenced by set_config().

00406 {
00407 #if defined(SIOCGIFHWADDR)
00408    int x,s;
00409    char eid_str[20];
00410    struct ifreq ifr;
00411 
00412    s = socket(AF_INET, SOCK_STREAM, 0);
00413    if (s > 0) {
00414       x = 0;
00415       for(x=0;x<10;x++) {
00416          memset(&ifr, 0, sizeof(ifr));
00417          snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
00418          if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
00419             memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
00420             ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
00421             close(s);
00422             return;
00423          }
00424         }
00425       close(s);
00426    }
00427 #else
00428 #if defined(ifa_broadaddr) && !defined(SOLARIS)
00429    char eid_str[20];
00430    struct ifaddrs *ifap;
00431    
00432    if (getifaddrs(&ifap) == 0) {
00433       struct ifaddrs *p;
00434       for (p = ifap; p; p = p->ifa_next) {
00435          if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
00436             struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
00437             memcpy(&(global_eid.eid), sdp->sdl_data + sdp->sdl_nlen, 6);
00438             ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), p->ifa_name);
00439             freeifaddrs(ifap);
00440             return;
00441          }
00442       }
00443       freeifaddrs(ifap);
00444    }
00445 #endif
00446 #endif
00447    ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
00448 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

00470 {
00471    int tid;
00472    tid = get_trans_id();
00473    if (tid < 1)
00474       return -1;
00475    trans->strans = tid;
00476    trans->dtrans = 0;
00477    trans->iseqno = 0;
00478    trans->oiseqno = 0;
00479    trans->oseqno = 0;
00480    trans->aseqno = 0;
00481    ast_clear_flag(trans, FLAG_FINAL);  
00482    return 0;
00483 }

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

Definition at line 2081 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02082 {
02083    char tmp[256];
02084    if (oldkey)
02085       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02086    else
02087       snprintf(tmp, sizeof(tmp), "%s", newkey);
02088    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02089    ast_db_put(secretpath, "secret", tmp);
02090    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02091    ast_db_put(secretpath, "secretexpiry", tmp);
02092 }

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

Definition at line 4422 of file pbx_dundi.c.

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

04423 {
04424    struct ast_config *cfg;
04425    struct ast_variable *v;
04426    char *cat;
04427    int format;
04428    int x;
04429    char hn[MAXHOSTNAMELEN] = "";
04430    struct ast_hostent he;
04431    struct hostent *hp;
04432    struct sockaddr_in sin2;
04433    static int last_port = 0;
04434    int globalpcmodel = 0;
04435    dundi_eid testeid;
04436 
04437    dundi_ttl = DUNDI_DEFAULT_TTL;
04438    dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
04439    any_peer = NULL;
04440    
04441    cfg = ast_config_load(config_file);
04442    
04443    if (!cfg) {
04444       ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
04445       return -1;
04446    }
04447    ipaddr[0] = '\0';
04448    if (!gethostname(hn, sizeof(hn)-1)) {
04449       hp = ast_gethostbyname(hn, &he);
04450       if (hp) {
04451          memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
04452          ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
04453       } else
04454          ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
04455    } else
04456       ast_log(LOG_WARNING, "Unable to get host name!\n");
04457    AST_LIST_LOCK(&peers);
04458    reset_global_eid();
04459    global_storehistory = 0;
04460    ast_copy_string(secretpath, "dundi", sizeof(secretpath));
04461    v = ast_variable_browse(cfg, "general");
04462    while(v) {
04463       if (!strcasecmp(v->name, "port")){ 
04464          sin->sin_port = ntohs(atoi(v->value));
04465          if(last_port==0){
04466             last_port=sin->sin_port;
04467          } else if(sin->sin_port != last_port)
04468             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
04469       } else if (!strcasecmp(v->name, "bindaddr")) {
04470          struct hostent *hp;
04471          struct ast_hostent he;
04472          hp = ast_gethostbyname(v->value, &he);
04473          if (hp) {
04474             memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
04475          } else
04476             ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
04477       } else if (!strcasecmp(v->name, "authdebug")) {
04478          authdebug = ast_true(v->value);
04479       } else if (!strcasecmp(v->name, "ttl")) {
04480          if ((sscanf(v->value, "%30d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
04481             dundi_ttl = x;
04482          } else {
04483             ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
04484                v->value, v->lineno, DUNDI_DEFAULT_TTL);
04485          }
04486       } else if (!strcasecmp(v->name, "autokill")) {
04487          if (sscanf(v->value, "%30d", &x) == 1) {
04488             if (x >= 0)
04489                global_autokilltimeout = x;
04490             else
04491                ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
04492          } else if (ast_true(v->value)) {
04493             global_autokilltimeout = DEFAULT_MAXMS;
04494          } else {
04495             global_autokilltimeout = 0;
04496          }
04497       } else if (!strcasecmp(v->name, "entityid")) {
04498          if (!dundi_str_to_eid(&testeid, v->value))
04499             global_eid = testeid;
04500          else
04501             ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
04502       } else if (!strcasecmp(v->name, "tos")) {
04503          if (sscanf(v->value, "%30d", &format) == 1)
04504             tos = format & 0xff;
04505          else if (!strcasecmp(v->value, "lowdelay"))
04506             tos = IPTOS_LOWDELAY;
04507          else if (!strcasecmp(v->value, "throughput"))
04508             tos = IPTOS_THROUGHPUT;
04509          else if (!strcasecmp(v->value, "reliability"))
04510             tos = IPTOS_RELIABILITY;
04511 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04512          else if (!strcasecmp(v->value, "mincost"))
04513             tos = IPTOS_MINCOST;
04514 #endif
04515          else if (!strcasecmp(v->value, "none"))
04516             tos = 0;
04517          else
04518 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04519             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
04520 #else
04521             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', or 'none'\n", v->lineno);
04522 #endif
04523       } else if (!strcasecmp(v->name, "department")) {
04524          ast_copy_string(dept, v->value, sizeof(dept));
04525       } else if (!strcasecmp(v->name, "organization")) {
04526          ast_copy_string(org, v->value, sizeof(org));
04527       } else if (!strcasecmp(v->name, "locality")) {
04528          ast_copy_string(locality, v->value, sizeof(locality));
04529       } else if (!strcasecmp(v->name, "stateprov")) {
04530          ast_copy_string(stateprov, v->value, sizeof(stateprov));
04531       } else if (!strcasecmp(v->name, "country")) {
04532          ast_copy_string(country, v->value, sizeof(country));
04533       } else if (!strcasecmp(v->name, "email")) {
04534          ast_copy_string(email, v->value, sizeof(email));
04535       } else if (!strcasecmp(v->name, "phone")) {
04536          ast_copy_string(phone, v->value, sizeof(phone));
04537       } else if (!strcasecmp(v->name, "storehistory")) {
04538          global_storehistory = ast_true(v->value);
04539       } else if (!strcasecmp(v->name, "cachetime")) {
04540          if ((sscanf(v->value, "%30d", &x) == 1)) {
04541             dundi_cache_time = x;
04542          } else {
04543             ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
04544                v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
04545          }
04546       }
04547       v = v->next;
04548    }
04549    AST_LIST_UNLOCK(&peers);
04550    mark_mappings();
04551    v = ast_variable_browse(cfg, "mappings");
04552    while(v) {
04553       build_mapping(v->name, v->value);
04554       v = v->next;
04555    }
04556    prune_mappings();
04557    mark_peers();
04558    cat = ast_category_browse(cfg, NULL);
04559    while(cat) {
04560       if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
04561          /* Entries */
04562          if (!dundi_str_to_eid(&testeid, cat))
04563             build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
04564          else if (!strcasecmp(cat, "*")) {
04565             build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel);
04566             any_peer = find_peer(NULL);
04567          } else
04568             ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
04569       }
04570       cat = ast_category_browse(cfg, cat);
04571    }
04572    prune_peers();
04573    ast_config_destroy(cfg);
04574    load_password();
04575    if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
04576       dundi_precache_full();
04577    return 0;
04578 }

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

Definition at line 2038 of file pbx_dundi.c.

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

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

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

Definition at line 2378 of file pbx_dundi.c.

References rescomp().

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

02379 {
02380    qsort(results, count, sizeof(results[0]), rescomp);
02381 }

static int start_network_thread ( void   )  [static]

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

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

00321 {
00322    if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) 
00323       return DUNDI_PROTO_IAX;
00324    else if (!strcasecmp(str, "SIP"))
00325       return DUNDI_PROTO_SIP;
00326    else if (!strcasecmp(str, "H323"))
00327       return DUNDI_PROTO_H323;
00328    else
00329       return -1;
00330 }

static char* tech2str ( int  tech  )  [static]

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

00305 {
00306    switch(tech) {
00307    case DUNDI_PROTO_NONE:
00308       return "None";
00309    case DUNDI_PROTO_IAX:
00310       return "IAX2";
00311    case DUNDI_PROTO_SIP:
00312       return "SIP";
00313    case DUNDI_PROTO_H323:
00314       return "H323";
00315    default:
00316       return "Unknown";
00317    }
00318 }

static int unload_module ( void   )  [static]

Definition at line 4580 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_switch, io, io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), sched, and sched_context_destroy().

04581 {
04582    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid, previous_clearcachethreadid = clearcachethreadid;
04583    ast_module_user_hangup_all();
04584 
04585    /* Stop all currently running threads */
04586    dundi_shutdown = 1;
04587    if (previous_netthreadid != AST_PTHREADT_NULL) {
04588       pthread_kill(previous_netthreadid, SIGURG);
04589       pthread_join(previous_netthreadid, NULL);
04590    }
04591    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04592       pthread_kill(previous_precachethreadid, SIGURG);
04593       pthread_join(previous_precachethreadid, NULL);
04594    }
04595    if (previous_clearcachethreadid != AST_PTHREADT_NULL) {
04596       pthread_cancel(previous_clearcachethreadid);
04597       pthread_join(previous_clearcachethreadid, NULL);
04598    }
04599    
04600    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04601    ast_unregister_switch(&dundi_switch);
04602    ast_custom_function_unregister(&dundi_function);
04603    close(netsocket);
04604    io_context_destroy(io);
04605    sched_context_destroy(sched);
04606 
04607    mark_mappings();
04608    prune_mappings();
04609    mark_peers();
04610    prune_peers();
04611 
04612    return 0;
04613 }

static void unregister_request ( struct dundi_request dr  )  [static]

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

03506 {
03507    AST_LIST_LOCK(&peers);
03508    AST_LIST_REMOVE(&requests, dr, list);
03509    AST_LIST_UNLOCK(&peers);
03510 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1289 of file pbx_dundi.c.

References aes_decrypt_key128(), aes_encrypt_key128(), ast_encrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), ast_sign_bin, build_iv(), dundi_eid_to_str(), 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().

01290 {
01291    unsigned char key[16];
01292    struct ast_key *ekey, *skey;
01293    char eid_str[20];
01294    int res;
01295    if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
01296       build_iv(key);
01297       aes_encrypt_key128(key, &peer->us_ecx);
01298       aes_decrypt_key128(key, &peer->us_dcx);
01299       ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
01300       if (!ekey) {
01301          ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
01302             peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01303          return -1;
01304       }
01305       skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
01306       if (!skey) {
01307          ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
01308             peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01309          return -1;
01310       }
01311       if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
01312          ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
01313          return -1;
01314       }
01315       if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
01316          ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
01317          return -1;
01318       }
01319       peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
01320       peer->sentfullkey = 0;
01321       /* Looks good */
01322       time(&peer->keyexpire);
01323       peer->keyexpire += dundi_key_ttl;
01324    }
01325    return 0;
01326 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

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

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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4685 of file pbx_dundi.c.

int authdebug = 0 [static]

Definition at line 118 of file pbx_dundi.c.

pthread_t clearcachethreadid = AST_PTHREADT_NULL [static]

Definition at line 115 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2808 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

char country[80] [static]

Definition at line 130 of file pbx_dundi.c.

Referenced by handle_mfcr2_show_variants(), and ind_load_module().

char cursecret[80] [static]

Definition at line 134 of file pbx_dundi.c.

char debug_usage[] [static]

Initial value:

 
"Usage: dundi debug\n"
"       Enables dumping of DUNDi packets for debugging purposes\n"

Definition at line 2738 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 124 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 126 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 121 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 120 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 138 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4412 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 119 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 117 of file pbx_dundi.c.

char email[80] [static]

Definition at line 131 of file pbx_dundi.c.

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

Definition at line 137 of file pbx_dundi.c.

Referenced by find_peer(), and set_config().

char flush_usage[] [static]

Initial value:

"Usage: dundi flush [stats]\n"
"       Flushes DUNDi answer cache, used primarily for debug.  If\n"
"'stats' is present, clears timer statistics instead of normal\n"
"operation.\n"

Definition at line 2802 of file pbx_dundi.c.

int global_autokilltimeout = 0 [static]

Definition at line 122 of file pbx_dundi.c.

dundi_eid global_eid [static]

Definition at line 123 of file pbx_dundi.c.

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

int global_storehistory = 0 [static]

Definition at line 125 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 110 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 135 of file pbx_dundi.c.

Referenced by realtime_update_peer().

char locality[80] [static]

Definition at line 128 of file pbx_dundi.c.

char lookup_usage[] [static]

Initial value:

"Usage: dundi lookup <number>[@context] [bypass]\n"
"       Lookup the given number within the given DUNDi context\n"
"(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
"keyword is specified.\n"

Definition at line 2784 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 112 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 113 of file pbx_dundi.c.

char no_debug_usage[] [static]

Initial value:

 
"Usage: dundi no debug\n"
"       Disables dumping of DUNDi packets for debugging purposes\n"

Definition at line 2742 of file pbx_dundi.c.

char no_store_history_usage[] [static]

Initial value:

 
"Usage: dundi no store history\n"
"       Disables storing of DUNDi requests and times for debugging\n"
"purposes\n"

Definition at line 2751 of file pbx_dundi.c.

char org[80] [static]

Definition at line 127 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 132 of file pbx_dundi.c.

Referenced by privacy_exec().

char precache_usage[] [static]

Initial value:

"Usage: dundi precache <number>[@context]\n"
"       Lookup the given number within the given DUNDi context\n"
"(or e164 if none is specified) and precaches the results to any\n"
"upstream DUNDi push servers.\n"

Definition at line 2790 of file pbx_dundi.c.

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 114 of file pbx_dundi.c.

char query_usage[] [static]

Initial value:

"Usage: dundi query <entity>[@context]\n"
"       Attempts to retrieve contact information for a specific\n"
"DUNDi entity identifier (EID) within a given DUNDi context (or\n"
"e164 if none is specified).\n"

Definition at line 2796 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 136 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 111 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 133 of file pbx_dundi.c.

char show_entityid_usage[] [static]

Initial value:

 
"Usage: dundi show entityid\n"
"       Displays the global entityid for this host.\n"

Definition at line 2772 of file pbx_dundi.c.

char show_mappings_usage[] [static]

Initial value:

 
"Usage: dundi show mappings\n"
"       Lists all known DUNDi mappings.\n"

Definition at line 2764 of file pbx_dundi.c.

char show_peer_usage[] [static]

Initial value:

 
"Usage: dundi show peer [peer]\n"
"       Provide a detailed description of a specifid DUNDi peer.\n"

Definition at line 2776 of file pbx_dundi.c.

char show_peers_usage[] [static]

Initial value:

 
"Usage: dundi show peers\n"
"       Lists all known DUNDi peers.\n"

Definition at line 2756 of file pbx_dundi.c.

char show_precache_usage[] [static]

Initial value:

 
"Usage: dundi show precache\n"
"       Lists all known DUNDi scheduled precache updates.\n"

Definition at line 2768 of file pbx_dundi.c.

char show_requests_usage[] [static]

Initial value:

 
"Usage: dundi show requests\n"
"       Lists all known pending DUNDi requests.\n"

Definition at line 2780 of file pbx_dundi.c.

char show_trans_usage[] [static]

Initial value:

 
"Usage: dundi show trans\n"
"       Lists all known DUNDi transactions.\n"

Definition at line 2760 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 129 of file pbx_dundi.c.

char store_history_usage[] [static]

Initial value:

 
"Usage: dundi store history\n"
"       Enables storing of DUNDi requests and times for debugging\n"
"purposes\n"

Definition at line 2746 of file pbx_dundi.c.

int tos = 0 [static]

Definition at line 116 of file pbx_dundi.c.


Generated on Sat Aug 6 00:40:02 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7