Mon Nov 24 15:34:47 2008

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  dundi_hint_metadata
struct  dundi_mapping
struct  dundi_packet
struct  dundi_peer
struct  dundi_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_transaction
struct  permission

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

Functions

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 AST_LIST_HEAD_NOLOCK_STATIC (alltrans, dundi_transaction)
static AST_LIST_HEAD_NOLOCK_STATIC (requests, dundi_request)
static AST_LIST_HEAD_NOLOCK_STATIC (mappings, dundi_mapping)
static AST_LIST_HEAD_STATIC (pcq, dundi_precache_queue)
static AST_LIST_HEAD_STATIC (peers, dundi_peer)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Distributed Universal Number Discovery (DUNDi)",.load=load_module,.unload=unload_module,.reload=reload,)
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, unsigned long 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, unsigned long 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_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 dundi_peerany_peer
 Wildcard peer.
static int authdebug = 0
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 98 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 83 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

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

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 103 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 88 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 91 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 94 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 92 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 93 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 90 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 95 of file pbx_dundi.c.

Referenced by create_transaction(), and dundi_encrypt().

#define FLAG_STOREHIST   (1 << 6)

Record historic performance

Definition at line 96 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 %-10.10s %-8.8s %-15.15s\n"

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

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

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

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

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

#define KEY_IN   1

Definition at line 107 of file pbx_dundi.c.

#define KEY_OUT   0

Definition at line 106 of file pbx_dundi.c.

#define MAX_OPTS   128

Definition at line 3961 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 81 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

Definition at line 79 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 abort_request ( struct dundi_request dr  )  [static]

Definition at line 3364 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03365 {
03366    struct dundi_transaction *trans;
03367 
03368    AST_LIST_LOCK(&peers);
03369    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03370       /* This will remove the transaction from the list */
03371       destroy_trans(trans, 0);
03372    }
03373    AST_LIST_UNLOCK(&peers);
03374 }

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

Definition at line 1974 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(), LOG_WARNING, and sched.

Referenced by handle_frame().

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

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

Definition at line 3948 of file pbx_dundi.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

03949 {
03950    struct permission *perm;
03951 
03952    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03953       return;
03954 
03955    strcpy(perm->name, s);
03956    perm->allow = allow;
03957 
03958    AST_LIST_INSERT_TAIL(permlist, perm, list);
03959 }

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

Definition at line 3321 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, LOG_DEBUG, and dundi_transaction::ttl.

Referenced by build_transactions().

03322 {
03323    struct dundi_transaction *trans;
03324    int x;
03325    char eid_str[20];
03326    char eid_str2[20];
03327 
03328    /* Ignore if not registered */
03329    if (!p->addr.sin_addr.s_addr)
03330       return 0;
03331    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03332       return 0;
03333    if (ast_strlen_zero(dr->number))
03334       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);
03335    else
03336       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);
03337    trans = create_transaction(p);
03338    if (!trans)
03339       return -1;
03340    trans->parent = dr;
03341    trans->ttl = ttl;
03342    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03343       trans->eids[x] = *avoid[x];
03344    trans->eidcount = x;
03345    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03346    
03347    return 0;
03348 }

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

Definition at line 1251 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_transaction::retranstimer, dundi_transaction::them_eid, and dundi_transaction::us_eid.

Referenced by create_transaction().

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

static AST_LIST_HEAD_NOLOCK_STATIC ( alltrans  ,
dundi_transaction   
) [static]

static AST_LIST_HEAD_NOLOCK_STATIC ( requests  ,
dundi_request   
) [static]

static AST_LIST_HEAD_NOLOCK_STATIC ( mappings  ,
dundi_mapping   
) [static]

static AST_LIST_HEAD_STATIC ( pcq  ,
dundi_precache_queue   
) [static]

static AST_LIST_HEAD_STATIC ( peers  ,
dundi_peer   
) [static]

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Distributed Universal Number Discovery (DUNDi)"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

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

Definition at line 3485 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03486 {
03487    /* Idea is that we're calculating a checksum which is independent of
03488       the order that the EID's are listed in */
03489    unsigned long acrc32 = 0;
03490    int x;
03491    for (x=0;avoid[x];x++) {
03492       /* Order doesn't matter */
03493       if (avoid[x+1]) {
03494          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03495       }
03496    }
03497    return acrc32;
03498 }

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

Definition at line 501 of file pbx_dundi.c.

References ast_random().

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

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

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

Definition at line 3963 of file pbx_dundi.c.

References ast_calloc, 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, LOG_WARNING, map, MAX_OPTS, str2tech(), and t.

Referenced by set_config().

03964 {
03965    char *t, *fields[MAX_OPTS];
03966    struct dundi_mapping *map;
03967    int x;
03968    int y;
03969 
03970    t = ast_strdupa(value);
03971       
03972    AST_LIST_TRAVERSE(&mappings, map, list) {
03973       /* Find a double match */
03974       if (!strcasecmp(map->dcontext, name) && 
03975          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
03976            (!value[strlen(map->lcontext)] || 
03977             (value[strlen(map->lcontext)] == ','))))
03978          break;
03979    }
03980    if (!map) {
03981       if (!(map = ast_calloc(1, sizeof(*map))))
03982          return;
03983       AST_LIST_INSERT_HEAD(&mappings, map, list);
03984       map->dead = 1;
03985    }
03986    map->options = 0;
03987    memset(fields, 0, sizeof(fields));
03988    x = 0;
03989    while (t && x < MAX_OPTS) {
03990       fields[x++] = t;
03991       t = strchr(t, ',');
03992       if (t) {
03993          *t = '\0';
03994          t++;
03995       }
03996    } /* Russell was here, arrrr! */
03997    if ((x == 1) && ast_strlen_zero(fields[0])) {
03998       /* Placeholder mapping */
03999       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04000       map->dead = 0;
04001    } else if (x >= 4) {
04002       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
04003       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
04004       if ((sscanf(fields[1], "%d", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) {
04005          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
04006          if ((map->tech = str2tech(fields[2]))) {
04007             map->dead = 0;
04008          }
04009       } else {
04010          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
04011       }
04012       for (y = 4;y < x; y++) {
04013          if (!strcasecmp(fields[y], "nounsolicited"))
04014             map->options |= DUNDI_FLAG_NOUNSOLICITED;
04015          else if (!strcasecmp(fields[y], "nocomunsolicit"))
04016             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
04017          else if (!strcasecmp(fields[y], "residential"))
04018             map->options |= DUNDI_FLAG_RESIDENTIAL;
04019          else if (!strcasecmp(fields[y], "commercial"))
04020             map->options |= DUNDI_FLAG_COMMERCIAL;
04021          else if (!strcasecmp(fields[y], "mobile"))
04022             map->options |= DUNDI_FLAG_MOBILE;
04023          else if (!strcasecmp(fields[y], "nopartial"))
04024             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
04025          else
04026             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
04027       }
04028    } else 
04029       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
04030 }

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

Definition at line 4114 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_SCHED_DEL, destroy_permissions(), dundi_eid_cmp(), DUNDI_PORT, dundi_peer::eid, global_eid, hp, ast_variable::name, ast_variable::next, peers, populate_addr(), sched, and ast_variable::value.

04115 {
04116    struct dundi_peer *peer;
04117    struct ast_hostent he;
04118    struct hostent *hp;
04119    dundi_eid testeid;
04120    int needregister=0;
04121    char eid_str[20];
04122 
04123    AST_LIST_LOCK(&peers);
04124    AST_LIST_TRAVERSE(&peers, peer, list) {
04125       if (!dundi_eid_cmp(&peer->eid, eid)) { 
04126          break;
04127       }
04128    }
04129    if (!peer) {
04130       /* Add us into the list */
04131       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04132          AST_LIST_UNLOCK(&peers);
04133          return;
04134       }
04135       peer->registerid = -1;
04136       peer->registerexpire = -1;
04137       peer->qualifyid = -1;
04138       peer->addr.sin_family = AF_INET;
04139       peer->addr.sin_port = htons(DUNDI_PORT);
04140       populate_addr(peer, eid);
04141       AST_LIST_INSERT_HEAD(&peers, peer, list);
04142    }
04143    peer->dead = 0;
04144    peer->eid = *eid;
04145    peer->us_eid = global_eid;
04146    destroy_permissions(&peer->permit);
04147    destroy_permissions(&peer->include);
04148    AST_SCHED_DEL(sched, peer->registerid);
04149    for (; v; v = v->next) {
04150       if (!strcasecmp(v->name, "inkey")) {
04151          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04152       } else if (!strcasecmp(v->name, "outkey")) {
04153          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04154       } else if (!strcasecmp(v->name, "host")) {
04155          if (!strcasecmp(v->value, "dynamic")) {
04156             peer->dynamic = 1;
04157          } else {
04158             hp = ast_gethostbyname(v->value, &he);
04159             if (hp) {
04160                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04161                peer->dynamic = 0;
04162             } else {
04163                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04164                peer->dead = 1;
04165             }
04166          }
04167       } else if (!strcasecmp(v->name, "ustothem")) {
04168          if (!dundi_str_to_eid(&testeid, v->value))
04169             peer->us_eid = testeid;
04170          else
04171             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04172       } else if (!strcasecmp(v->name, "include")) {
04173          append_permission(&peer->include, v->value, 1);
04174       } else if (!strcasecmp(v->name, "permit")) {
04175          append_permission(&peer->permit, v->value, 1);
04176       } else if (!strcasecmp(v->name, "noinclude")) {
04177          append_permission(&peer->include, v->value, 0);
04178       } else if (!strcasecmp(v->name, "deny")) {
04179          append_permission(&peer->permit, v->value, 0);
04180       } else if (!strcasecmp(v->name, "register")) {
04181          needregister = ast_true(v->value);
04182       } else if (!strcasecmp(v->name, "order")) {
04183          if (!strcasecmp(v->value, "primary"))
04184             peer->order = 0;
04185          else if (!strcasecmp(v->value, "secondary"))
04186             peer->order = 1;
04187          else if (!strcasecmp(v->value, "tertiary"))
04188             peer->order = 2;
04189          else if (!strcasecmp(v->value, "quartiary"))
04190             peer->order = 3;
04191          else {
04192             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);
04193          }
04194       } else if (!strcasecmp(v->name, "qualify")) {
04195          if (!strcasecmp(v->value, "no")) {
04196             peer->maxms = 0;
04197          } else if (!strcasecmp(v->value, "yes")) {
04198             peer->maxms = DEFAULT_MAXMS;
04199          } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
04200             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04201                dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04202             peer->maxms = 0;
04203          }
04204       } else if (!strcasecmp(v->name, "model")) {
04205          if (!strcasecmp(v->value, "inbound"))
04206             peer->model = DUNDI_MODEL_INBOUND;
04207          else if (!strcasecmp(v->value, "outbound")) 
04208             peer->model = DUNDI_MODEL_OUTBOUND;
04209          else if (!strcasecmp(v->value, "symmetric"))
04210             peer->model = DUNDI_MODEL_SYMMETRIC;
04211          else if (!strcasecmp(v->value, "none"))
04212             peer->model = 0;
04213          else {
04214             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04215                v->value, v->lineno);
04216          }
04217       } else if (!strcasecmp(v->name, "precache")) {
04218          if (!strcasecmp(v->value, "inbound"))
04219             peer->pcmodel = DUNDI_MODEL_INBOUND;
04220          else if (!strcasecmp(v->value, "outbound")) 
04221             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04222          else if (!strcasecmp(v->value, "symmetric"))
04223             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04224          else if (!strcasecmp(v->value, "none"))
04225             peer->pcmodel = 0;
04226          else {
04227             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04228                v->value, v->lineno);
04229          }
04230       }
04231    }
04232    (*globalpcmode) |= peer->pcmodel;
04233    if (!peer->model && !peer->pcmodel) {
04234       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04235          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04236       peer->dead = 1;
04237    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04238       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04239          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04240       peer->dead = 1;
04241    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04242       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04243          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04244       peer->dead = 1;
04245    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04246       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04247          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04248    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04249       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", 
04250          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04251    } else { 
04252       if (needregister) {
04253          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04254       }
04255       qualify_peer(peer, 1);
04256    }
04257    AST_LIST_UNLOCK(&peers);
04258 }

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

Definition at line 2064 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

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

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 3376 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(), LOG_DEBUG, and peers.

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

03377 {
03378    struct dundi_peer *p;
03379    int x;
03380    int res;
03381    int pass;
03382    int allowconnect;
03383    char eid_str[20];
03384    AST_LIST_LOCK(&peers);
03385    AST_LIST_TRAVERSE(&peers, p, list) {
03386       if (modeselect == 1) {
03387          /* Send the precache to push upstreams only! */
03388          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03389          allowconnect = 1;
03390       } else {
03391          /* Normal lookup / EID query */
03392          pass = has_permission(&p->include, dr->dcontext);
03393          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03394       }
03395       if (skip) {
03396          if (!dundi_eid_cmp(skip, &p->eid))
03397             pass = 0;
03398       }
03399       if (pass) {
03400          if (p->order <= order) {
03401             /* Check order first, then check cache, regardless of
03402                omissions, this gets us more likely to not have an
03403                affected answer. */
03404             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03405                res = 0;
03406                /* Make sure we haven't already seen it and that it won't
03407                   affect our answer */
03408                for (x=0;avoid[x];x++) {
03409                   if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
03410                      /* If not a direct connection, it affects our answer */
03411                      if (directs && !directs[x]) 
03412                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03413                      break;
03414                   }
03415                }
03416                /* Make sure we can ask */
03417                if (allowconnect) {
03418                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03419                      /* Check for a matching or 0 cache entry */
03420                      append_transaction(dr, p, ttl, avoid);
03421                   } else
03422                      ast_log(LOG_DEBUG, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03423                }
03424             }
03425             *foundcache |= res;
03426          } else if (!*skipped || (p->order < *skipped))
03427             *skipped = p->order;
03428       }
03429    }
03430    AST_LIST_UNLOCK(&peers);
03431 }

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

Definition at line 1199 of file pbx_dundi.c.

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

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

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

Definition at line 1127 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3350 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, dr, DUNDI_COMMAND_CANCEL, dundi_send(), and peers.

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03351 {
03352    struct dundi_transaction *trans;
03353 
03354    AST_LIST_LOCK(&peers);
03355    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03356       /* Orphan transaction from request */
03357       trans->parent = NULL;
03358       /* Send final cancel */
03359       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03360    }
03361    AST_LIST_UNLOCK(&peers);
03362 }

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

Definition at line 1450 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, LOG_DEBUG, LOG_NOTICE, and option_debug.

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

static void check_password ( void   )  [static]

Definition at line 2131 of file pbx_dundi.c.

References build_secret(), and save_secret().

Referenced by network_thread().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3471 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dr, and peers.

Referenced by dundi_lookup_internal().

03472 {
03473    struct dundi_request *cur;
03474 
03475    AST_LIST_LOCK(&peers);
03476    AST_LIST_TRAVERSE(&requests, cur, list) {
03477       if (cur == dr)
03478          break;
03479    }
03480    AST_LIST_UNLOCK(&peers);
03481    
03482    return cur ? 1 : 0;
03483 }

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

Definition at line 2323 of file pbx_dundi.c.

References complete_peer_helper().

02324 {
02325    return complete_peer_helper(line, word, pos, state, 3);
02326 }

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

Definition at line 2301 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, peers, and s.

Referenced by complete_peer_4().

02302 {
02303    int which=0, len;
02304    char *ret = NULL;
02305    struct dundi_peer *p;
02306    char eid_str[20];
02307 
02308    if (pos != rpos)
02309       return NULL;
02310    AST_LIST_LOCK(&peers);
02311    len = strlen(word);
02312    AST_LIST_TRAVERSE(&peers, p, list) {
02313       const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02314       if (!strncasecmp(word, s, len) && ++which > state) {
02315          ret = ast_strdup(s);
02316          break;
02317       }
02318    }
02319    AST_LIST_UNLOCK(&peers);
02320    return ret;
02321 }

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

Definition at line 2831 of file pbx_dundi.c.

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

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

02832 {
02833    struct dundi_transaction *trans;
02834    int tid;
02835    
02836    /* Don't allow creation of transactions to non-registered peers */
02837    if (p && !p->addr.sin_addr.s_addr)
02838       return NULL;
02839    tid = get_trans_id();
02840    if (tid < 1)
02841       return NULL;
02842    trans = ast_calloc(1, sizeof(*trans));
02843    if (trans) {
02844       if (global_storehistory) {
02845          trans->start = ast_tvnow();
02846          ast_set_flag(trans, FLAG_STOREHIST);
02847       }
02848       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02849       trans->autokillid = -1;
02850       if (p) {
02851          apply_peer(trans, p);
02852          if (!p->sentfullkey)
02853             ast_set_flag(trans, FLAG_SENDFULLKEY);
02854       }
02855       trans->strans = tid;
02856       AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02857    }
02858    return trans;
02859 }

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

Definition at line 1342 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

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

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

Definition at line 1504 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, and AST_LIST_TRAVERSE.

Referenced by handle_command_response().

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 3913 of file pbx_dundi.c.

References free, and map.

Referenced by prune_mappings().

03914 {
03915    free(map);
03916 }

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

Definition at line 2877 of file pbx_dundi.c.

References AST_LIST_REMOVE, AST_SCHED_DEL, free, and sched.

Referenced by ack_trans().

02878 {
02879    if (pack->parent)
02880       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02881    AST_SCHED_DEL(sched, pack->retransid);
02882    if (needfree)
02883       free(pack);
02884 }

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

Definition at line 1963 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, AST_SCHED_DEL, free, and sched.

Referenced by ack_trans(), and handle_frame().

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

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 3902 of file pbx_dundi.c.

References AST_SCHED_DEL, destroy_permissions(), destroy_trans(), free, and sched.

Referenced by prune_peers().

03903 {
03904    AST_SCHED_DEL(sched, peer->registerid);
03905    if (peer->regtrans)
03906       destroy_trans(peer->regtrans, 0);
03907    AST_SCHED_DEL(sched, peer->qualifyid);
03908    destroy_permissions(&peer->permit);
03909    destroy_permissions(&peer->include);
03910    free(peer);
03911 }

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

Definition at line 3894 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by build_peer(), and destroy_peer().

03895 {
03896    struct permission *perm;
03897 
03898    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03899       free(perm);
03900 }

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

Definition at line 2886 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_strlen_zero(), ast_test_flag, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, free, LOG_NOTICE, peers, 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().

02887 {
02888    struct dundi_peer *peer;
02889    int ms;
02890    int x;
02891    int cnt;
02892    char eid_str[20];
02893    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02894       AST_LIST_TRAVERSE(&peers, peer, list) {
02895          if (peer->regtrans == trans)
02896             peer->regtrans = NULL;
02897          if (peer->qualtrans == trans) {
02898             if (fromtimeout) {
02899                if (peer->lastms > -1)
02900                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02901                peer->lastms = -1;
02902             } else {
02903                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02904                if (ms < 1)
02905                   ms = 1;
02906                if (ms < peer->maxms) {
02907                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02908                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02909                } else if (peer->lastms < peer->maxms) {
02910                   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);
02911                }
02912                peer->lastms = ms;
02913             }
02914             peer->qualtrans = NULL;
02915          }
02916          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02917             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02918                if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
02919                   peer->avgms = 0;
02920                   cnt = 0;
02921                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02922                      free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02923                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02924                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02925                      peer->lookups[x] = peer->lookups[x-1];
02926                      if (peer->lookups[x]) {
02927                         peer->avgms += peer->lookuptimes[x];
02928                         cnt++;
02929                      }
02930                   }
02931                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
02932                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
02933                   if (peer->lookups[0]) {
02934                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
02935                      peer->avgms += peer->lookuptimes[0];
02936                      cnt++;
02937                   }
02938                   if (cnt)
02939                      peer->avgms /= cnt;
02940                }
02941             }
02942          }
02943       }
02944    }
02945    if (trans->parent) {
02946       /* Unlink from parent if appropriate */
02947       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
02948       if (AST_LIST_EMPTY(&trans->parent->trans)) {
02949          /* Wake up sleeper */
02950          if (trans->parent->pfds[1] > -1) {
02951             write(trans->parent->pfds[1], "killa!", 6);
02952          }
02953       }
02954    }
02955    /* Unlink from all trans */
02956    AST_LIST_REMOVE(&alltrans, trans, all);
02957    destroy_packets(&trans->packets);
02958    destroy_packets(&trans->lasttrans);
02959    AST_SCHED_DEL(sched, trans->autokillid);
02960    if (trans->thread) {
02961       /* If used by a thread, mark as dead and be done */
02962       ast_set_flag(trans, FLAG_DEAD);
02963    } else
02964       free(trans);
02965 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3206 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03207 {
03208    struct dundi_transaction *trans;
03209    AST_LIST_LOCK(&peers);
03210    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03211       dundi_discover(trans);
03212    }
03213    AST_LIST_UNLOCK(&peers);
03214    return 0;
03215 }

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

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

03062 {
03063    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03064    char eid_str[20];
03065    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03066       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03067    trans->autokillid = -1;
03068    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03069    return 0;
03070 }

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

Definition at line 4059 of file pbx_dundi.c.

References qualify_peer().

Referenced by qualify_peer().

04060 {
04061    struct dundi_peer *peer = (struct dundi_peer *)data;
04062    peer->qualifyid = -1;
04063    qualify_peer(peer, 0);
04064    return 0;
04065 }

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

Definition at line 4033 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, and sched.

04034 {
04035    struct dundi_ie_data ied;
04036    struct dundi_peer *peer = (struct dundi_peer *)data;
04037    char eid_str[20];
04038    char eid_str2[20];
04039    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));
04040    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04041    /* Destroy old transaction if there is one */
04042    if (peer->regtrans)
04043       destroy_trans(peer->regtrans, 0);
04044    peer->regtrans = create_transaction(peer);
04045    if (peer->regtrans) {
04046       ast_set_flag(peer->regtrans, FLAG_ISREG);
04047       memset(&ied, 0, sizeof(ied));
04048       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04049       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04050       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04051       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04052       
04053    } else
04054       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));
04055 
04056    return 0;
04057 }

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

Note:
Called with the peers list already locked

Definition at line 1276 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

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

Definition at line 374 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00375 {
00376    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00377 }

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

Definition at line 751 of file pbx_dundi.c.

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

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

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

Definition at line 1039 of file pbx_dundi.c.

References ast_calloc, 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, LOG_DEBUG, LOG_WARNING, dundi_query_state::maps, 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().

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

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04305 {
04306    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04307 }

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

Definition at line 278 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

00279 {
00280    if (dundidebug)
00281       ast_verbose("%s", data);
00282 }

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

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

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

Definition at line 3094 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, 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, sched, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by discover_transactions().

03095 {
03096    struct dundi_ie_data ied;
03097    int x;
03098    if (!trans->parent) {
03099       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03100       return -1;
03101    }
03102    memset(&ied, 0, sizeof(ied));
03103    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03104    if (!dundi_eid_zero(&trans->us_eid))
03105       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03106    for (x=0;x<trans->eidcount;x++)
03107       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03108    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03109    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03110    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03111    if (trans->parent->cbypass)
03112       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03113    if (trans->autokilltimeout)
03114       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03115    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03116 }

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

Definition at line 2218 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02219 {
02220    if (argc != 2)
02221       return RESULT_SHOWUSAGE;
02222    dundidebug = 1;
02223    ast_cli(fd, "DUNDi Debugging Enabled\n");
02224    return RESULT_SUCCESS;
02225 }

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

Definition at line 2345 of file pbx_dundi.c.

References ast_cli(), context, dr, dundi_flags2str(), dundi_lookup(), MAX_RESULTS, RESULT_SHOWUSAGE, RESULT_SUCCESS, and sort_results().

02346 {
02347    int res;
02348    char tmp[256];
02349    char fs[80] = "";
02350    char *context;
02351    int x;
02352    int bypass = 0;
02353    struct dundi_result dr[MAX_RESULTS];
02354    struct timeval start;
02355    if ((argc < 3) || (argc > 4))
02356       return RESULT_SHOWUSAGE;
02357    if (argc > 3) {
02358       if (!strcasecmp(argv[3], "bypass"))
02359          bypass=1;
02360       else
02361          return RESULT_SHOWUSAGE;
02362    }
02363    ast_copy_string(tmp, argv[2], sizeof(tmp));
02364    context = strchr(tmp, '@');
02365    if (context) {
02366       *context = '\0';
02367       context++;
02368    }
02369    start = ast_tvnow();
02370    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02371    
02372    if (res < 0) 
02373       ast_cli(fd, "DUNDi lookup returned error.\n");
02374    else if (!res) 
02375       ast_cli(fd, "DUNDi lookup returned no results.\n");
02376    else
02377       sort_results(dr, res);
02378    for (x=0;x<res;x++) {
02379       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));
02380       ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02381    }
02382    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02383    return RESULT_SUCCESS;
02384 }

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

Definition at line 2386 of file pbx_dundi.c.

References ast_cli(), context, dundi_precache(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02387 {
02388    int res;
02389    char tmp[256];
02390    char *context;
02391    struct timeval start;
02392    if ((argc < 3) || (argc > 3))
02393       return RESULT_SHOWUSAGE;
02394    ast_copy_string(tmp, argv[2], sizeof(tmp));
02395    context = strchr(tmp, '@');
02396    if (context) {
02397       *context = '\0';
02398       context++;
02399    }
02400    start = ast_tvnow();
02401    res = dundi_precache(context, tmp);
02402    
02403    if (res < 0) 
02404       ast_cli(fd, "DUNDi precache returned error.\n");
02405    else if (!res) 
02406       ast_cli(fd, "DUNDi precache returned no error.\n");
02407    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02408    return RESULT_SUCCESS;
02409 }

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

Definition at line 2411 of file pbx_dundi.c.

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

02412 {
02413    int res;
02414    char tmp[256];
02415    char *context;
02416    dundi_eid eid;
02417    struct dundi_entity_info dei;
02418    if ((argc < 3) || (argc > 3))
02419       return RESULT_SHOWUSAGE;
02420    if (dundi_str_to_eid(&eid, argv[2])) {
02421       ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
02422       return RESULT_SHOWUSAGE;
02423    }
02424    ast_copy_string(tmp, argv[2], sizeof(tmp));
02425    context = strchr(tmp, '@');
02426    if (context) {
02427       *context = '\0';
02428       context++;
02429    }
02430    res = dundi_query_eid(&dei, context, eid);
02431    if (res < 0) 
02432       ast_cli(fd, "DUNDi Query EID returned error.\n");
02433    else if (!res) 
02434       ast_cli(fd, "DUNDi Query EID returned no results.\n");
02435    else {
02436       ast_cli(fd, "DUNDi Query EID succeeded:\n");
02437       ast_cli(fd, "Department:      %s\n", dei.orgunit);
02438       ast_cli(fd, "Organization:    %s\n", dei.org);
02439       ast_cli(fd, "City/Locality:   %s\n", dei.locality);
02440       ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
02441       ast_cli(fd, "Country:         %s\n", dei.country);
02442       ast_cli(fd, "E-mail:          %s\n", dei.email);
02443       ast_cli(fd, "Phone:           %s\n", dei.phone);
02444       ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
02445    }
02446    return RESULT_SUCCESS;
02447 }

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

Definition at line 2227 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02228 {
02229    if (argc != 3)
02230       return RESULT_SHOWUSAGE;
02231    global_storehistory = 1;
02232    ast_cli(fd, "DUNDi History Storage Enabled\n");
02233    return RESULT_SUCCESS;
02234 }

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

Definition at line 1383 of file pbx_dundi.c.

References ast_log(), ast_set_flag, ast_test_flag, build_iv(), 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, len, LOG_DEBUG, LOG_NOTICE, dundi_transaction::them_eid, update_key(), and dundi_transaction::us_eid.

Referenced by dundi_send().

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

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

Definition at line 284 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

00285 {
00286    ast_log(LOG_WARNING, "%s", data);
00287 }

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

04310 {
04311    struct dundi_result results[MAX_RESULTS];
04312    int res;
04313    int x=0;
04314    char req[1024];
04315    struct ast_app *dial;
04316    
04317    if (!strncasecmp(context, "macro-", 6)) {
04318       if (!chan) {   
04319          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04320          return -1;
04321       }
04322       /* If done as a macro, use macro extension */
04323       if (!strcasecmp(exten, "s")) {
04324          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04325          if (ast_strlen_zero(exten))
04326             exten = chan->macroexten;
04327          if (ast_strlen_zero(exten))
04328             exten = chan->exten;
04329          if (ast_strlen_zero(exten)) { 
04330             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04331             return -1;
04332          }
04333       }
04334       if (ast_strlen_zero(data))
04335          data = "e164";
04336    } else {
04337       if (ast_strlen_zero(data))
04338          data = context;
04339    }
04340    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04341    if (res > 0) {
04342       sort_results(results, res);
04343       for (x=0;x<res;x++) {
04344          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04345             if (!--priority)
04346                break;
04347          }
04348       }
04349    }
04350    if (x < res) {
04351       /* Got a hit! */
04352       snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
04353       dial = pbx_findapp("Dial");
04354       if (dial)
04355          res = pbx_exec(chan, dial, req);
04356    } else
04357       res = -1;
04358    return res;
04359 }

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04300 {
04301    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04302 }

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

Definition at line 2236 of file pbx_dundi.c.

References ast_cli(), ast_db_deltree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, DUNDI_TIMING_HISTORY, free, peers, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02237 {
02238    int stats = 0;
02239    if ((argc < 2) || (argc > 3))
02240       return RESULT_SHOWUSAGE;
02241    if (argc > 2) {
02242       if (!strcasecmp(argv[2], "stats"))
02243          stats = 1;
02244       else
02245          return RESULT_SHOWUSAGE;
02246    }
02247    if (stats) {
02248       /* Flush statistics */
02249       struct dundi_peer *p;
02250       int x;
02251       AST_LIST_LOCK(&peers);
02252       AST_LIST_TRAVERSE(&peers, p, list) {
02253          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02254             if (p->lookups[x])
02255                free(p->lookups[x]);
02256             p->lookups[x] = NULL;
02257             p->lookuptimes[x] = 0;
02258          }
02259          p->avgms = 0;
02260       }
02261       AST_LIST_UNLOCK(&peers);
02262    } else {
02263       ast_db_deltree("dundi/cache", NULL);
02264       ast_cli(fd, "DUNDi Cache Flushed\n");
02265    }
02266    return RESULT_SUCCESS;
02267 }

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

04261 {
04262    struct dundi_result results[MAX_RESULTS];
04263    int res;
04264    int x;
04265    int found = 0;
04266    if (!strncasecmp(context, "macro-", 6)) {
04267       if (!chan) {   
04268          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04269          return -1;
04270       }
04271       /* If done as a macro, use macro extension */
04272       if (!strcasecmp(exten, "s")) {
04273          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04274          if (ast_strlen_zero(exten))
04275             exten = chan->macroexten;
04276          if (ast_strlen_zero(exten))
04277             exten = chan->exten;
04278          if (ast_strlen_zero(exten)) { 
04279             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04280             return -1;
04281          }
04282       }
04283       if (ast_strlen_zero(data))
04284          data = "e164";
04285    } else {
04286       if (ast_strlen_zero(data))
04287          data = context;
04288    }
04289    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04290    for (x=0;x<res;x++) {
04291       if (ast_test_flag(results + x, flag))
04292          found++;
04293    }
04294    if (found >= priority)
04295       return 1;
04296    return 0;
04297 }

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

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

Referenced by dundi_discover().

03073 {
03074    struct dundi_peer *p;
03075    if (!dundi_eid_cmp(eid, us)) {
03076       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03077       return;
03078    }
03079    AST_LIST_LOCK(&peers);
03080    AST_LIST_TRAVERSE(&peers, p, list) {
03081       if (!dundi_eid_cmp(&p->eid, eid)) {
03082          if (has_permission(&p->include, context))
03083             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03084          else
03085             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03086          break;
03087       }
03088    }
03089    if (!p)
03090       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03091    AST_LIST_UNLOCK(&peers);
03092 }

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

03603 {
03604    struct dundi_hint_metadata hmd;
03605    dundi_eid *avoid[1] = { NULL, };
03606    int direct[1] = { 0, };
03607    int expiration = dundi_cache_time;
03608    memset(&hmd, 0, sizeof(hmd));
03609    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03610    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03611 }

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

References ast_channel::_softhangup, abort_request(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, 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, optimize_transactions(), register_request(), dundi_request::root_eid, and unregister_request().

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

03501 {
03502    int res;
03503    struct dundi_request dr, *pending;
03504    dundi_eid *rooteid=NULL;
03505    int x;
03506    int ttlms;
03507    int ms;
03508    int foundcache;
03509    int skipped=0;
03510    int order=0;
03511    char eid_str[20];
03512    struct timeval start;
03513    
03514    /* Don't do anthing for a hungup channel */
03515    if (chan && chan->_softhangup)
03516       return 0;
03517 
03518    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03519 
03520    for (x=0;avoid[x];x++)
03521       rooteid = avoid[x];
03522    /* Now perform real check */
03523    memset(&dr, 0, sizeof(dr));
03524    if (pipe(dr.pfds)) {
03525       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03526       return -1;
03527    }
03528    dr.dr = result;
03529    dr.hmd = hmd;
03530    dr.maxcount = maxret;
03531    dr.expiration = *expiration;
03532    dr.cbypass = cbypass;
03533    dr.crc32 = avoid_crc32(avoid);
03534    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03535    ast_copy_string(dr.number, number, sizeof(dr.number));
03536    if (rooteid)
03537       dr.root_eid = *rooteid;
03538    res = register_request(&dr, &pending);
03539    if (res) {
03540       /* Already a request */
03541       if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03542          /* This is on behalf of someone else.  Go ahead and close this out since
03543             they'll get their answer anyway. */
03544          ast_log(LOG_DEBUG, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03545             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03546          close(dr.pfds[0]);
03547          close(dr.pfds[1]);
03548          return -2;
03549       } else {
03550          /* Wait for the cache to populate */
03551          ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n",
03552             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03553          start = ast_tvnow();
03554          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03555             /* XXX Would be nice to have a way to poll/select here XXX */
03556             /* XXX this is a busy wait loop!!! */
03557             usleep(1);
03558          }
03559          /* Continue on as normal, our cache should kick in */
03560       }
03561    }
03562    /* Create transactions */
03563    do {
03564       order = skipped;
03565       skipped = 0;
03566       foundcache = 0;
03567       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03568    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03569    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03570       do this earlier because we didn't know if we were going to have transactions
03571       or not. */
03572    if (!ttl) {
03573       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03574       abort_request(&dr);
03575       unregister_request(&dr);
03576       close(dr.pfds[0]);
03577       close(dr.pfds[1]);
03578       return 0;
03579    }
03580       
03581    /* Optimize transactions */
03582    optimize_transactions(&dr, order);
03583    /* Actually perform transactions */
03584    discover_transactions(&dr);
03585    /* Wait for transaction to come back */
03586    start = ast_tvnow();
03587    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03588       ms = 100;
03589       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03590    }
03591    if (chan && chan->_softhangup)
03592       ast_log(LOG_DEBUG, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03593    cancel_request(&dr);
03594    unregister_request(&dr);
03595    res = dr.respcount;
03596    *expiration = dr.expiration;
03597    close(dr.pfds[0]);
03598    close(dr.pfds[1]);
03599    return res;
03600 }

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

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, 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, dundi_transaction::flags, map, pbx_substitute_variables_varshead(), tech2str(), and dundi_transaction::us_eid.

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 600 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, dundi_transaction::flags, free, LOG_DEBUG, dundi_query_state::maps, MAX_RESULTS, dundi_query_state::nocache, dundi_query_state::nummaps, peers, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_query().

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

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04362 {
04363    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04364 }

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

Definition at line 2269 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02270 {
02271    if (argc != 3)
02272       return RESULT_SHOWUSAGE;
02273    dundidebug = 0;
02274    ast_cli(fd, "DUNDi Debugging Disabled\n");
02275    return RESULT_SUCCESS;
02276 }

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

Definition at line 2278 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02279 {
02280    if (argc != 4)
02281       return RESULT_SHOWUSAGE;
02282    global_storehistory = 0;
02283    ast_cli(fd, "DUNDi History Storage Disabled\n");
02284    return RESULT_SUCCESS;
02285 }

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

Pre-cache to push upstream peers.

Definition at line 3746 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03747 {
03748    dundi_eid *avoid[1] = { NULL, };
03749    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03750 }

static void dundi_precache_full ( void   )  [static]

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

03650 {
03651    struct dundi_mapping *cur;
03652    struct ast_context *con;
03653    struct ast_exten *e;
03654 
03655    AST_LIST_TRAVERSE(&mappings, cur, list) {
03656       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03657       ast_rdlock_contexts();
03658       con = ast_walk_contexts(NULL);
03659       while (con) {
03660          if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
03661             /* Found the match, now queue them all up */
03662             ast_lock_context(con);
03663             e = ast_walk_context_extensions(con, NULL);
03664             while (e) {
03665                reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03666                e = ast_walk_context_extensions(con, e);
03667             }
03668             ast_unlock_context(con);
03669          }
03670          con = ast_walk_contexts(con);
03671       }
03672       ast_unlock_contexts();
03673    }
03674 }

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

Definition at line 3676 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, LOG_DEBUG, LOG_NOTICE, MAX_RESULTS, optimize_transactions(), peers, precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

03677 {
03678    struct dundi_request dr;
03679    struct dundi_hint_metadata hmd;
03680    struct dundi_result dr2[MAX_RESULTS];
03681    struct timeval start;
03682    struct dundi_mapping *maps = NULL, *cur;
03683    int nummaps = 0;
03684    int foundanswers;
03685    int foundcache, skipped, ttlms, ms;
03686    if (!context)
03687       context = "e164";
03688    ast_log(LOG_DEBUG, "Precache internal (%s@%s)!\n", number, context);
03689 
03690    AST_LIST_LOCK(&peers);
03691    AST_LIST_TRAVERSE(&mappings, cur, list) {
03692       if (!strcasecmp(cur->dcontext, context))
03693          nummaps++;
03694    }
03695    if (nummaps) {
03696       maps = alloca(nummaps * sizeof(*maps));
03697       nummaps = 0;
03698       if (maps) {
03699          AST_LIST_TRAVERSE(&mappings, cur, list) {
03700             if (!strcasecmp(cur->dcontext, context))
03701                maps[nummaps++] = *cur;
03702          }
03703       }
03704    }
03705    AST_LIST_UNLOCK(&peers);
03706    if (!nummaps || !maps)
03707       return -1;
03708    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03709    memset(&dr2, 0, sizeof(dr2));
03710    memset(&dr, 0, sizeof(dr));
03711    memset(&hmd, 0, sizeof(hmd));
03712    dr.dr = dr2;
03713    ast_copy_string(dr.number, number, sizeof(dr.number));
03714    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03715    dr.maxcount = MAX_RESULTS;
03716    dr.expiration = dundi_cache_time;
03717    dr.hmd = &hmd;
03718    dr.pfds[0] = dr.pfds[1] = -1;
03719    pipe(dr.pfds);
03720    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03721    optimize_transactions(&dr, 0);
03722    foundanswers = 0;
03723    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03724    if (foundanswers) {
03725       if (dr.expiration > 0) 
03726          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03727       else
03728          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03729    }
03730    start = ast_tvnow();
03731    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03732       if (dr.pfds[0] > -1) {
03733          ms = 100;
03734          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03735       } else
03736          usleep(1);
03737    }
03738    cancel_request(&dr);
03739    if (dr.pfds[0] > -1) {
03740       close(dr.pfds[0]);
03741       close(dr.pfds[1]);
03742    }
03743    return 0;
03744 }

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

Definition at line 664 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, peers, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.

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

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

Definition at line 887 of file pbx_dundi.c.

References ast_clear_flag_nonstd, dr, dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_transaction::flags, ies, MAX_RESULTS, s, and tech2str().

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

Definition at line 3184 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, 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, sched, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by query_transactions().

03185 {
03186    struct dundi_ie_data ied;
03187    int x;
03188    if (!trans->parent) {
03189       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03190       return -1;
03191    }
03192    memset(&ied, 0, sizeof(ied));
03193    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03194    if (!dundi_eid_zero(&trans->us_eid))
03195       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03196    for (x=0;x<trans->eidcount;x++)
03197       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03198    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03199    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03200    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03201    if (trans->autokilltimeout)
03202       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03203    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03204 }

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

Retrieve information on a specific EID.

Definition at line 3799 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03800 {
03801    dundi_eid *avoid[1] = { NULL, };
03802    struct dundi_hint_metadata hmd;
03803    memset(&hmd, 0, sizeof(hmd));
03804    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03805 }

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

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

03753 {
03754    int res;
03755    struct dundi_request dr;
03756    dundi_eid *rooteid=NULL;
03757    int x;
03758    int ttlms;
03759    int skipped=0;
03760    int foundcache=0;
03761    struct timeval start;
03762    
03763    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03764 
03765    for (x=0;avoid[x];x++)
03766       rooteid = avoid[x];
03767    /* Now perform real check */
03768    memset(&dr, 0, sizeof(dr));
03769    dr.hmd = hmd;
03770    dr.dei = dei;
03771    dr.pfds[0] = dr.pfds[1] = -1;
03772    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03773    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03774    if (rooteid)
03775       dr.root_eid = *rooteid;
03776    /* Create transactions */
03777    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03778 
03779    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03780       do this earlier because we didn't know if we were going to have transactions
03781       or not. */
03782    if (!ttl) {
03783       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03784       return 0;
03785    }
03786       
03787    /* Optimize transactions */
03788    optimize_transactions(&dr, 9999);
03789    /* Actually perform transactions */
03790    query_transactions(&dr);
03791    /* Wait for transaction to come back */
03792    start = ast_tvnow();
03793    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03794       usleep(1);
03795    res = dr.respcount;
03796    return res;
03797 }

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

Definition at line 697 of file pbx_dundi.c.

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

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

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

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

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

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

Definition at line 2967 of file pbx_dundi.c.

References ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, destroy_trans(), dundi_xmit(), FLAG_ISQUAL, LOG_NOTICE, and peers.

Referenced by dundi_send().

02968 {
02969    struct dundi_packet *pack = (struct dundi_packet *)data;
02970    int res;
02971    AST_LIST_LOCK(&peers);
02972    if (pack->retrans < 1) {
02973       pack->retransid = -1;
02974       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
02975          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
02976             ast_inet_ntoa(pack->parent->addr.sin_addr), 
02977             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
02978       destroy_trans(pack->parent, 1);
02979       res = 0;
02980    } else {
02981       /* Decrement retransmission, try again */
02982       pack->retrans--;
02983       dundi_xmit(pack);
02984       res = 1;
02985    }
02986    AST_LIST_UNLOCK(&peers);
02987    return res;
02988 }

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

Definition at line 2990 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_transaction::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_transaction::iseqno, len, LOG_NOTICE, dundi_transaction::oseqno, dundi_transaction::retranstimer, sched, dundi_transaction::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().

02991 {
02992    struct dundi_packet *pack;
02993    int res;
02994    int len;
02995    char eid_str[20];
02996    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
02997    /* Reserve enough space for encryption */
02998    if (ast_test_flag(trans, FLAG_ENCRYPT))
02999       len += 384;
03000    pack = ast_calloc(1, len);
03001    if (pack) {
03002       pack->h = (struct dundi_hdr *)(pack->data);
03003       if (cmdresp != DUNDI_COMMAND_ACK) {
03004          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
03005          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
03006          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
03007       }
03008       pack->parent = trans;
03009       pack->h->strans = htons(trans->strans);
03010       pack->h->dtrans = htons(trans->dtrans);
03011       pack->h->iseqno = trans->iseqno;
03012       pack->h->oseqno = trans->oseqno;
03013       pack->h->cmdresp = cmdresp;
03014       pack->datalen = sizeof(struct dundi_hdr);
03015       if (ied) {
03016          memcpy(pack->h->ies, ied->buf, ied->pos);
03017          pack->datalen += ied->pos;
03018       } 
03019       if (final) {
03020          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
03021          ast_set_flag(trans, FLAG_FINAL);
03022       }
03023       pack->h->cmdflags = flags;
03024       if (cmdresp != DUNDI_COMMAND_ACK) {
03025          trans->oseqno++;
03026          trans->oseqno = trans->oseqno % 256;
03027       }
03028       trans->aseqno = trans->iseqno;
03029       /* If we have their public key, encrypt */
03030       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
03031          switch(cmdresp) {
03032          case DUNDI_COMMAND_REGREQ:
03033          case DUNDI_COMMAND_REGRESPONSE:
03034          case DUNDI_COMMAND_DPDISCOVER:
03035          case DUNDI_COMMAND_DPRESPONSE:
03036          case DUNDI_COMMAND_EIDQUERY:
03037          case DUNDI_COMMAND_EIDRESPONSE:
03038          case DUNDI_COMMAND_PRECACHERQ:
03039          case DUNDI_COMMAND_PRECACHERP:
03040             if (dundidebug)
03041                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
03042             res = dundi_encrypt(trans, pack);
03043             break;
03044          default:
03045             res = 0;
03046          }
03047       } else 
03048          res = 0;
03049       if (!res) 
03050          res = dundi_xmit(pack);
03051       if (res)
03052          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03053             
03054       if (cmdresp == DUNDI_COMMAND_ACK)
03055          free(pack);
03056       return res;
03057    }
03058    return -1;
03059 }

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

Definition at line 2616 of file pbx_dundi.c.

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

02617 {
02618    char eid_str[20];
02619    if (argc != 3)
02620       return RESULT_SHOWUSAGE;
02621    AST_LIST_LOCK(&peers);
02622    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02623    AST_LIST_UNLOCK(&peers);
02624    ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
02625    return RESULT_SUCCESS;
02626 }

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

Definition at line 2650 of file pbx_dundi.c.

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

02651 {
02652 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02653 #define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
02654    struct dundi_mapping *map;
02655    char fs[256];
02656    if (argc != 3)
02657       return RESULT_SHOWUSAGE;
02658    AST_LIST_LOCK(&peers);
02659    ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02660    AST_LIST_TRAVERSE(&mappings, map, list) {
02661       ast_cli(fd, FORMAT, map->dcontext, map->weight, 
02662          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02663          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02664    }
02665    AST_LIST_UNLOCK(&peers);
02666    return RESULT_SUCCESS;
02667 #undef FORMAT
02668 #undef FORMAT2
02669 }

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

Definition at line 2449 of file pbx_dundi.c.

References dundi_peer::addr, ast_cli(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_strlen_zero(), dundi_eid_to_str(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::eid, model2str(), peers, and RESULT_SHOWUSAGE.

02450 {
02451    struct dundi_peer *peer;
02452    struct permission *p;
02453    char *order;
02454    char eid_str[20];
02455    int x, cnt;
02456    
02457    if (argc != 4)
02458       return RESULT_SHOWUSAGE;
02459    AST_LIST_LOCK(&peers);
02460    AST_LIST_TRAVERSE(&peers, peer, list) {
02461       if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), argv[3]))
02462          break;
02463    }
02464    if (peer) {
02465       switch(peer->order) {
02466       case 0:
02467          order = "Primary";
02468          break;
02469       case 1:
02470          order = "Secondary";
02471          break;
02472       case 2:
02473          order = "Tertiary";
02474          break;
02475       case 3:
02476          order = "Quartiary";
02477          break;
02478       default:
02479          order = "Unknown";
02480       }
02481       ast_cli(fd, "Peer:    %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02482       ast_cli(fd, "Model:   %s\n", model2str(peer->model));
02483       ast_cli(fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02484       ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02485       ast_cli(fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02486       ast_cli(fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02487       ast_cli(fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02488       if (!AST_LIST_EMPTY(&peer->include))
02489          ast_cli(fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02490       AST_LIST_TRAVERSE(&peer->include, p, list)
02491          ast_cli(fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02492       if (!AST_LIST_EMPTY(&peer->permit))
02493          ast_cli(fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02494       AST_LIST_TRAVERSE(&peer->permit, p, list)
02495          ast_cli(fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02496       cnt = 0;
02497       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02498          if (peer->lookups[x]) {
02499             if (!cnt)
02500                ast_cli(fd, "Last few query times:\n");
02501             ast_cli(fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02502             cnt++;
02503          }
02504       }
02505       if (cnt)
02506          ast_cli(fd, "Average query time: %d ms\n", peer->avgms);
02507    } else
02508       ast_cli(fd, "No such peer '%s'\n", argv[3]);
02509    AST_LIST_UNLOCK(&peers);
02510    return RESULT_SUCCESS;
02511 }

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

Definition at line 2513 of file pbx_dundi.c.

References dundi_peer::addr, ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_eid_to_str(), dundi_peer::eid, FORMAT, FORMAT2, model2str(), peers, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02514 {
02515 #define FORMAT2 "%-20.20s %-15.15s     %-10.10s %-8.8s %-15.15s\n"
02516 #define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
02517    struct dundi_peer *peer;
02518    int registeredonly=0;
02519    char avgms[20];
02520    char eid_str[20];
02521    int online_peers = 0;
02522    int offline_peers = 0;
02523    int unmonitored_peers = 0;
02524    int total_peers = 0;
02525 
02526    if ((argc != 3) && (argc != 4) && (argc != 5))
02527       return RESULT_SHOWUSAGE;
02528    if ((argc == 4)) {
02529       if (!strcasecmp(argv[3], "registered")) {
02530          registeredonly = 1;
02531       } else
02532          return RESULT_SHOWUSAGE;
02533    }
02534    AST_LIST_LOCK(&peers);
02535    ast_cli(fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status");
02536    AST_LIST_TRAVERSE(&peers, peer, list) {
02537       char status[20];
02538       int print_line = -1;
02539       char srch[2000];
02540       total_peers++;
02541       if (registeredonly && !peer->addr.sin_addr.s_addr)
02542          continue;
02543       if (peer->maxms) {
02544          if (peer->lastms < 0) {
02545             strcpy(status, "UNREACHABLE");
02546             offline_peers++;
02547          }
02548          else if (peer->lastms > peer->maxms) {
02549             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02550             offline_peers++;
02551          }
02552          else if (peer->lastms) {
02553             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02554             online_peers++;
02555          }
02556          else {
02557             strcpy(status, "UNKNOWN");
02558             offline_peers++;
02559          }
02560       } else {
02561          strcpy(status, "Unmonitored");
02562          unmonitored_peers++;
02563       }
02564       if (peer->avgms) 
02565          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02566       else
02567          strcpy(avgms, "Unavail");
02568       snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02569                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02570                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02571 
02572                 if (argc == 5) {
02573                   if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) {
02574                         print_line = -1;
02575                    } else if (!strcasecmp(argv[3],"exclude") && !strstr(srch,argv[4])) {
02576                         print_line = 1;
02577                    } else if (!strcasecmp(argv[3],"begin") && !strncasecmp(srch,argv[4],strlen(argv[4]))) {
02578                         print_line = -1;
02579                    } else {
02580                         print_line = 0;
02581                   }
02582                 }
02583       
02584         if (print_line) {
02585          ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02586                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02587                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02588       }
02589    }
02590    ast_cli(fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02591    AST_LIST_UNLOCK(&peers);
02592    return RESULT_SUCCESS;
02593 #undef FORMAT
02594 #undef FORMAT2
02595 }

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

Definition at line 2671 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, FORMAT, FORMAT2, RESULT_SHOWUSAGE, RESULT_SUCCESS, and s.

02672 {
02673 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02674 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02675    struct dundi_precache_queue *qe;
02676    int h,m,s;
02677    time_t now;
02678    
02679    if (argc != 3)
02680       return RESULT_SHOWUSAGE;
02681    time(&now);
02682    ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
02683    AST_LIST_LOCK(&pcq);
02684    AST_LIST_TRAVERSE(&pcq, qe, list) {
02685       s = qe->expiration - now;
02686       h = s / 3600;
02687       s = s % 3600;
02688       m = s / 60;
02689       s = s % 60;
02690       ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
02691    }
02692    AST_LIST_UNLOCK(&pcq);
02693    
02694    return RESULT_SUCCESS;
02695 #undef FORMAT
02696 #undef FORMAT2
02697 }

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

Definition at line 2628 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::maxcount, dundi_request::number, peers, dundi_request::respcount, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_request::root_eid.

02629 {
02630 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02631 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02632    struct dundi_request *req;
02633    char eidstr[20];
02634    if (argc != 3)
02635       return RESULT_SHOWUSAGE;
02636    AST_LIST_LOCK(&peers);
02637    ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02638    AST_LIST_TRAVERSE(&requests, req, list) {
02639       ast_cli(fd, FORMAT, req->number, req->dcontext,
02640          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02641    }
02642    AST_LIST_UNLOCK(&peers);
02643    return RESULT_SUCCESS;
02644 #undef FORMAT
02645 #undef FORMAT2
02646 }

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

Definition at line 2597 of file pbx_dundi.c.

References dundi_transaction::addr, 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, peers, RESULT_SHOWUSAGE, RESULT_SUCCESS, and dundi_transaction::strans.

02598 {
02599 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02600 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02601    struct dundi_transaction *trans;
02602    if (argc != 3)
02603       return RESULT_SHOWUSAGE;
02604    AST_LIST_LOCK(&peers);
02605    ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02606    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02607       ast_cli(fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02608          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02609    }
02610    AST_LIST_UNLOCK(&peers);
02611    return RESULT_SUCCESS;
02612 #undef FORMAT
02613 #undef FORMAT2
02614 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

Definition at line 2861 of file pbx_dundi.c.

References ast_inet_ntoa(), ast_log(), dundi_showframe(), errno, and LOG_WARNING.

Referenced by dundi_reject(), dundi_rexmit(), and dundi_send().

02862 {
02863    int res;
02864    if (dundidebug)
02865       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02866    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02867    if (res < 0) {
02868       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02869          ast_inet_ntoa(pack->parent->addr.sin_addr),
02870          ntohs(pack->parent->addr.sin_port), strerror(errno));
02871    }
02872    if (res > 0)
02873       res = 0;
02874    return res;
02875 }

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

Definition at line 3807 of file pbx_dundi.c.

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

03808 {
03809    char *context;
03810    char *opts;
03811    int results;
03812    int x;
03813    int bypass = 0;
03814    struct ast_module_user *u;
03815    struct dundi_result dr[MAX_RESULTS];
03816 
03817    buf[0] = '\0';
03818 
03819    if (ast_strlen_zero(num)) {
03820       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03821       return -1;
03822    }
03823 
03824    u = ast_module_user_add(chan);
03825 
03826    context = strchr(num, '|');
03827    if (context) {
03828       *context++ = '\0';
03829       opts = strchr(context, '|');
03830       if (opts) {
03831          *opts++ = '\0';
03832          if (strchr(opts, 'b'))
03833             bypass = 1;
03834       }
03835    }
03836 
03837    if (ast_strlen_zero(context))
03838       context = "e164";
03839    
03840    results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
03841    if (results > 0) {
03842       sort_results(dr, results);
03843       for (x = 0; x < results; x++) {
03844          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03845             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03846             break;
03847          }
03848       }
03849    }
03850 
03851    ast_module_user_remove(u);
03852 
03853    return 0;
03854 }

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

Definition at line 1326 of file pbx_dundi.c.

References aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 483 of file pbx_dundi.c.

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

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

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

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

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

static int get_trans_id ( void   )  [static]

Definition at line 448 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_random(), and t.

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1534 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, any_peer, ast_calloc, ast_clear_flag_nonstd, 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, deep_copy_peer(), do_register_expire(), 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::eid, find_peer(), FLAG_ENCRYPT, dundi_transaction::flags, has_permission(), dundi_hdr::ies, ies, inaddrcmp(), LOG_DEBUG, LOG_NOTICE, LOG_WARNING, option_verbose, dundi_hdr::oseqno, peers, dundi_ie_data::pos, qualify_peer(), sched, tech2str(), dundi_transaction::them_eid, dundi_transaction::us_eid, and VERBOSE_PREFIX_3.

Referenced by handle_frame().

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

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

Definition at line 1995 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, LOG_DEBUG, dundi_transaction::oiseqno, and dundi_hdr::oseqno.

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

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

Definition at line 289 of file pbx_dundi.c.

References AST_LIST_TRAVERSE.

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

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

static int load_module ( void   )  [static]

Definition at line 4572 of file pbx_dundi.c.

References ast_cli_register_multiple(), ast_custom_function_register(), ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, 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.

04573 {
04574    int res = 0;
04575    struct sockaddr_in sin;
04576 
04577    dundi_set_output(dundi_debug_output);
04578    dundi_set_error(dundi_error_output);
04579    
04580    sin.sin_family = AF_INET;
04581    sin.sin_port = ntohs(DUNDI_PORT);
04582    sin.sin_addr.s_addr = INADDR_ANY;
04583 
04584    /* Make a UDP socket */
04585    io = io_context_create();
04586    sched = sched_context_create();
04587    
04588    if (!io || !sched) {
04589       ast_log(LOG_ERROR, "Out of memory\n");
04590       return -1;
04591    }
04592 
04593    if(set_config("dundi.conf",&sin))
04594       return AST_MODULE_LOAD_DECLINE;
04595 
04596    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04597    
04598    if (netsocket < 0) {
04599       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04600       return -1;
04601    }
04602    if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
04603       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));
04604       return -1;
04605    }
04606 
04607    if (option_verbose > 1)
04608       ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
04609 
04610    if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
04611       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
04612    
04613    res = start_network_thread();
04614    if (res) {
04615       ast_log(LOG_ERROR, "Unable to start network thread\n");
04616       close(netsocket);
04617       return -1;
04618    }
04619 
04620    if (option_verbose > 1)
04621       ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04622 
04623    ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04624    if (ast_register_switch(&dundi_switch))
04625       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04626    ast_custom_function_register(&dundi_function); 
04627    
04628    return res;
04629 }

static void load_password ( void   )  [static]

Definition at line 2092 of file pbx_dundi.c.

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

Referenced by set_config().

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

static void mark_mappings ( void   )  [static]

Definition at line 3883 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, map, and peers.

Referenced by set_config(), and unload_module().

03884 {
03885    struct dundi_mapping *map;
03886    
03887    AST_LIST_LOCK(&peers);
03888    AST_LIST_TRAVERSE(&mappings, map, list) {
03889       map->dead = 1;
03890    }
03891    AST_LIST_UNLOCK(&peers);
03892 }

static void mark_peers ( void   )  [static]

Definition at line 3873 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by set_config(), and unload_module().

03874 {
03875    struct dundi_peer *peer;
03876    AST_LIST_LOCK(&peers);
03877    AST_LIST_TRAVERSE(&peers, peer, list) {
03878       peer->dead = 1;
03879    }
03880    AST_LIST_UNLOCK(&peers);
03881 }

static char* model2str ( int  model  )  [static]

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

02288 {
02289    switch(model) {
02290    case DUNDI_MODEL_INBOUND:
02291       return "Inbound";
02292    case DUNDI_MODEL_OUTBOUND:
02293       return "Outbound";
02294    case DUNDI_MODEL_SYMMETRIC:
02295       return "Symmetric";
02296    default:
02297       return "Unknown";
02298    }
02299 }

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

Definition at line 2148 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, peers, sched, and socket_read().

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

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

Definition at line 3265 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(), peers, dundi_transaction::them_eid, and dundi_transaction::us_eid.

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

03266 {
03267    /* Minimize the message propagation through DUNDi by
03268       alerting the network to hops which should be not be considered */
03269    struct dundi_transaction *trans;
03270    struct dundi_peer *peer;
03271    dundi_eid tmp;
03272    int x;
03273    int needpush;
03274 
03275    AST_LIST_LOCK(&peers);
03276    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03277       /* Pop off the true root */
03278       if (trans->eidcount) {
03279          tmp = trans->eids[--trans->eidcount];
03280          needpush = 1;
03281       } else {
03282          tmp = trans->us_eid;
03283          needpush = 0;
03284       }
03285 
03286       AST_LIST_TRAVERSE(&peers, peer, list) {
03287          if (has_permission(&peer->include, dr->dcontext) && 
03288              dundi_eid_cmp(&peer->eid, &trans->them_eid) &&
03289             (peer->order <= order)) {
03290             /* For each other transaction, make sure we don't
03291                ask this EID about the others if they're not
03292                already in the list */
03293             if (!dundi_eid_cmp(&tmp, &peer->eid)) 
03294                x = -1;
03295             else {
03296                for (x=0;x<trans->eidcount;x++) {
03297                   if (!dundi_eid_cmp(&trans->eids[x], &peer->eid))
03298                      break;
03299                }
03300             }
03301             if (x == trans->eidcount) {
03302                /* Nope not in the list, if needed, add us at the end since we're the source */
03303                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03304                   trans->eids[trans->eidcount++] = peer->eid;
03305                   /* Need to insert the real root (or us) at the bottom now as
03306                      a requirement now.  */
03307                   needpush = 1;
03308                }
03309             }
03310          }
03311       }
03312       /* If necessary, push the true root back on the end */
03313       if (needpush)
03314          trans->eids[trans->eidcount++] = tmp;
03315    }
03316    AST_LIST_UNLOCK(&peers);
03317 
03318    return 0;
03319 }

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

Definition at line 4090 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, and sched.

Referenced by build_peer().

04091 {
04092    char data[256];
04093    char *c;
04094    int port, expire;
04095    char eid_str[20];
04096    dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
04097    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04098       c = strchr(data, ':');
04099       if (c) {
04100          *c = '\0';
04101          c++;
04102          if (sscanf(c, "%d:%d", &port, &expire) == 2) {
04103             /* Got it! */
04104             inet_aton(data, &peer->addr.sin_addr);
04105             peer->addr.sin_family = AF_INET;
04106             peer->addr.sin_port = htons(port);
04107             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04108          }
04109       }
04110    }
04111 }

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

Definition at line 3118 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, 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, dundi_hint_metadata::flags, LOG_WARNING, MAX_RESULTS, sched, dundi_transaction::them_eid, dundi_transaction::ttl, and dundi_transaction::us_eid.

Referenced by precache_transactions().

03119 {
03120    struct dundi_ie_data ied;
03121    int x, res;
03122    int max = 999999;
03123    int expiration = dundi_cache_time;
03124    int ouranswers=0;
03125    dundi_eid *avoid[1] = { NULL, };
03126    int direct[1] = { 0, };
03127    struct dundi_result dr[MAX_RESULTS];
03128    struct dundi_hint_metadata hmd;
03129    if (!trans->parent) {
03130       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03131       return -1;
03132    }
03133    memset(&hmd, 0, sizeof(hmd));
03134    memset(&dr, 0, sizeof(dr));
03135    /* Look up the answers we're going to include */
03136    for (x=0;x<mapcount;x++)
03137       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03138    if (ouranswers < 0)
03139       ouranswers = 0;
03140    for (x=0;x<ouranswers;x++) {
03141       if (dr[x].weight < max)
03142          max = dr[x].weight;
03143    }
03144    if (max) {
03145       /* If we do not have a canonical result, keep looking */
03146       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);
03147       if (res > 0) {
03148          /* Append answer in result */
03149          ouranswers += res;
03150       }
03151    }
03152    
03153    if (ouranswers > 0) {
03154       *foundanswers += ouranswers;
03155       memset(&ied, 0, sizeof(ied));
03156       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03157       if (!dundi_eid_zero(&trans->us_eid))
03158          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03159       for (x=0;x<trans->eidcount;x++)
03160          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03161       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03162       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03163       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03164       for (x=0;x<ouranswers;x++) {
03165          /* Add answers */
03166          if (dr[x].expiration && (expiration > dr[x].expiration))
03167             expiration = dr[x].expiration;
03168          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03169       }
03170       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03171       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03172       if (trans->autokilltimeout)
03173          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03174       if (expiration < *minexp)
03175          *minexp = expiration;
03176       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03177    } else {
03178       /* Oops, nothing to send... */
03179       destroy_trans(trans, 0);
03180       return 0;
03181    }
03182 }

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

Definition at line 3217 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, peers, precache_trans(), and dundi_transaction::thread.

Referenced by dundi_precache_internal().

03218 {
03219    struct dundi_transaction *trans;
03220 
03221    /* Mark all as "in thread" so they don't disappear */
03222    AST_LIST_LOCK(&peers);
03223    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03224       if (trans->thread)
03225          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03226       trans->thread = 1;
03227    }
03228    AST_LIST_UNLOCK(&peers);
03229 
03230    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03231       if (!ast_test_flag(trans, FLAG_DEAD))
03232          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03233    }
03234 
03235    /* Cleanup any that got destroyed in the mean time */
03236    AST_LIST_LOCK(&peers);
03237    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03238       trans->thread = 0;
03239       if (ast_test_flag(trans, FLAG_DEAD)) {
03240          ast_log(LOG_DEBUG, "Our transaction went away!\n");
03241          /* This is going to remove the transaction from the dundi_request's list, as well
03242           * as the global transactions list */
03243          destroy_trans(trans, 0);
03244       }
03245    }
03246    AST_LIST_TRAVERSE_SAFE_END
03247    AST_LIST_UNLOCK(&peers);
03248 
03249    return 0;
03250 }

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

Definition at line 2174 of file pbx_dundi.c.

References AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, AST_PTHREADT_NULL, context, dundi_precache(), and free.

Referenced by start_network_thread().

02175 {
02176    struct dundi_precache_queue *qe;
02177    time_t now;
02178    char context[256];
02179    char number[256];
02180    int run;
02181 
02182    while (!dundi_shutdown) {
02183       time(&now);
02184       run = 0;
02185       AST_LIST_LOCK(&pcq);
02186       if ((qe = AST_LIST_FIRST(&pcq))) {
02187          if (!qe->expiration) {
02188             /* Gone...  Remove... */
02189             AST_LIST_REMOVE_HEAD(&pcq, list);
02190             free(qe);
02191          } else if (qe->expiration < now) {
02192             /* Process this entry */
02193             qe->expiration = 0;
02194             ast_copy_string(context, qe->context, sizeof(context));
02195             ast_copy_string(number, qe->number, sizeof(number));
02196             run = 1;
02197          }
02198       }
02199       AST_LIST_UNLOCK(&pcq);
02200       if (run) {
02201          dundi_precache(context, number);
02202       } else
02203          sleep(1);
02204    }
02205 
02206    precachethreadid = AST_PTHREADT_NULL;
02207 
02208    return NULL;
02209 }

static void prune_mappings ( void   )  [static]

Definition at line 3933 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(), map, and peers.

Referenced by set_config(), and unload_module().

03934 {
03935    struct dundi_mapping *map;
03936 
03937    AST_LIST_LOCK(&peers);
03938    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
03939       if (map->dead) {
03940          AST_LIST_REMOVE_CURRENT(&mappings, list);
03941          destroy_map(map);
03942       }
03943    }
03944    AST_LIST_TRAVERSE_SAFE_END
03945    AST_LIST_UNLOCK(&peers);
03946 }

static void prune_peers ( void   )  [static]

Definition at line 3918 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_peer(), and peers.

03919 {
03920    struct dundi_peer *peer;
03921 
03922    AST_LIST_LOCK(&peers);
03923    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
03924       if (peer->dead) {
03925          AST_LIST_REMOVE_CURRENT(&peers, list);
03926          destroy_peer(peer);
03927       }
03928    }
03929    AST_LIST_TRAVERSE_SAFE_END
03930    AST_LIST_UNLOCK(&peers);
03931 }

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

Definition at line 4067 of file pbx_dundi.c.

References ast_sched_add(), AST_SCHED_DEL, ast_set_flag, create_transaction(), destroy_trans(), do_qualify(), DUNDI_COMMAND_NULL, dundi_send(), FLAG_ISQUAL, and sched.

Referenced by do_qualify(), and handle_command_response().

04068 {
04069    int when;
04070    AST_SCHED_DEL(sched, peer->qualifyid);
04071    if (peer->qualtrans)
04072       destroy_trans(peer->qualtrans, 0);
04073    peer->qualtrans = NULL;
04074    if (peer->maxms > 0) {
04075       when = 60000;
04076       if (peer->lastms < 0)
04077          when = 10000;
04078       if (schedonly)
04079          when = 5000;
04080       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04081       if (!schedonly)
04082          peer->qualtrans = create_transaction(peer);
04083       if (peer->qualtrans) {
04084          peer->qualtx = ast_tvnow();
04085          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04086          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04087       }
04088    }
04089 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3252 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

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

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

Definition at line 3433 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(), LOG_DEBUG, dundi_request::number, option_debug, peers, and dundi_request::root_eid.

Referenced by dundi_lookup_internal().

03434 {
03435    struct dundi_request *cur;
03436    int res=0;
03437    char eid_str[20];
03438    AST_LIST_LOCK(&peers);
03439    AST_LIST_TRAVERSE(&requests, cur, list) {
03440       if (option_debug)
03441          ast_log(LOG_DEBUG, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03442             dr->dcontext, dr->number);
03443       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03444           !strcasecmp(cur->number, dr->number) &&
03445           (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03446          ast_log(LOG_DEBUG, "Found existing query for '%s@%s' for '%s' crc '%08lx'\n", 
03447             cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03448          *pending = cur;
03449          res = 1;
03450          break;
03451       }
03452    }
03453    if (!res) {
03454       ast_log(LOG_DEBUG, "Registering request for '%s@%s' on behalf of '%s' crc '%08lx'\n", 
03455             dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03456       /* Go ahead and link us in since nobody else is searching for this */
03457       AST_LIST_INSERT_HEAD(&requests, dr, list);
03458       *pending = NULL;
03459    }
03460    AST_LIST_UNLOCK(&peers);
03461    return res;
03462 }

static int reload ( void   )  [static]

Definition at line 4565 of file pbx_dundi.c.

References set_config().

04566 {
04567    struct sockaddr_in sin;
04568    set_config("dundi.conf",&sin);
04569    return 0;
04570 }

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

Definition at line 3613 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, and len.

Referenced by dundi_precache_full(), and dundi_precache_internal().

03614 {
03615    int len;
03616    struct dundi_precache_queue *qe, *prev;
03617 
03618    AST_LIST_LOCK(&pcq);
03619    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03620       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03621          AST_LIST_REMOVE_CURRENT(&pcq, list);
03622          break;
03623       }
03624    }
03625    AST_LIST_TRAVERSE_SAFE_END
03626    if (!qe) {
03627       len = sizeof(*qe);
03628       len += strlen(number) + 1;
03629       len += strlen(context) + 1;
03630       if (!(qe = ast_calloc(1, len))) {
03631          AST_LIST_UNLOCK(&pcq);
03632          return;
03633       }
03634       strcpy(qe->number, number);
03635       qe->context = qe->number + strlen(number) + 1;
03636       strcpy(qe->context, context);
03637    }
03638    time(&qe->expiration);
03639    qe->expiration += expiration;
03640    if ((prev = AST_LIST_FIRST(&pcq))) {
03641       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03642          prev = AST_LIST_NEXT(prev, list);
03643       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03644    } else
03645       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03646    AST_LIST_UNLOCK(&pcq);
03647 }

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

Definition at line 2328 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02329 {
02330    const struct dundi_result *resa, *resb;
02331    resa = a;
02332    resb = b;
02333    if (resa->weight < resb->weight)
02334       return -1;
02335    if (resa->weight > resb->weight)
02336       return 1;
02337    return 0;
02338 }

static void reset_global_eid ( void   )  [static]

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

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

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

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

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

Definition at line 2079 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

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

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

Definition at line 4376 of file pbx_dundi.c.

References any_peer, ast_category_browse(), ast_config_destroy(), ast_config_load(), 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, peers, prune_mappings(), prune_peers(), reset_global_eid(), and ast_variable::value.

04377 {
04378    struct ast_config *cfg;
04379    struct ast_variable *v;
04380    char *cat;
04381    int format;
04382    int x;
04383    char hn[MAXHOSTNAMELEN] = "";
04384    struct ast_hostent he;
04385    struct hostent *hp;
04386    struct sockaddr_in sin2;
04387    static int last_port = 0;
04388    int globalpcmodel = 0;
04389    dundi_eid testeid;
04390 
04391    dundi_ttl = DUNDI_DEFAULT_TTL;
04392    dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
04393    any_peer = NULL;
04394    
04395    cfg = ast_config_load(config_file);
04396    
04397    if (!cfg) {
04398       ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
04399       return -1;
04400    }
04401    ipaddr[0] = '\0';
04402    if (!gethostname(hn, sizeof(hn)-1)) {
04403       hp = ast_gethostbyname(hn, &he);
04404       if (hp) {
04405          memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
04406          ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
04407       } else
04408          ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
04409    } else
04410       ast_log(LOG_WARNING, "Unable to get host name!\n");
04411    AST_LIST_LOCK(&peers);
04412    reset_global_eid();
04413    global_storehistory = 0;
04414    ast_copy_string(secretpath, "dundi", sizeof(secretpath));
04415    v = ast_variable_browse(cfg, "general");
04416    while(v) {
04417       if (!strcasecmp(v->name, "port")){ 
04418          sin->sin_port = ntohs(atoi(v->value));
04419          if(last_port==0){
04420             last_port=sin->sin_port;
04421          } else if(sin->sin_port != last_port)
04422             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
04423       } else if (!strcasecmp(v->name, "bindaddr")) {
04424          struct hostent *hp;
04425          struct ast_hostent he;
04426          hp = ast_gethostbyname(v->value, &he);
04427          if (hp) {
04428             memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
04429          } else
04430             ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
04431       } else if (!strcasecmp(v->name, "authdebug")) {
04432          authdebug = ast_true(v->value);
04433       } else if (!strcasecmp(v->name, "ttl")) {
04434          if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
04435             dundi_ttl = x;
04436          } else {
04437             ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
04438                v->value, v->lineno, DUNDI_DEFAULT_TTL);
04439          }
04440       } else if (!strcasecmp(v->name, "autokill")) {
04441          if (sscanf(v->value, "%d", &x) == 1) {
04442             if (x >= 0)
04443                global_autokilltimeout = x;
04444             else
04445                ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
04446          } else if (ast_true(v->value)) {
04447             global_autokilltimeout = DEFAULT_MAXMS;
04448          } else {
04449             global_autokilltimeout = 0;
04450          }
04451       } else if (!strcasecmp(v->name, "entityid")) {
04452          if (!dundi_str_to_eid(&testeid, v->value))
04453             global_eid = testeid;
04454          else
04455             ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
04456       } else if (!strcasecmp(v->name, "tos")) {
04457          if (sscanf(v->value, "%d", &format) == 1)
04458             tos = format & 0xff;
04459          else if (!strcasecmp(v->value, "lowdelay"))
04460             tos = IPTOS_LOWDELAY;
04461          else if (!strcasecmp(v->value, "throughput"))
04462             tos = IPTOS_THROUGHPUT;
04463          else if (!strcasecmp(v->value, "reliability"))
04464             tos = IPTOS_RELIABILITY;
04465 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04466          else if (!strcasecmp(v->value, "mincost"))
04467             tos = IPTOS_MINCOST;
04468 #endif
04469          else if (!strcasecmp(v->value, "none"))
04470             tos = 0;
04471          else
04472 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04473             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
04474 #else
04475             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', or 'none'\n", v->lineno);
04476 #endif
04477       } else if (!strcasecmp(v->name, "department")) {
04478          ast_copy_string(dept, v->value, sizeof(dept));
04479       } else if (!strcasecmp(v->name, "organization")) {
04480          ast_copy_string(org, v->value, sizeof(org));
04481       } else if (!strcasecmp(v->name, "locality")) {
04482          ast_copy_string(locality, v->value, sizeof(locality));
04483       } else if (!strcasecmp(v->name, "stateprov")) {
04484          ast_copy_string(stateprov, v->value, sizeof(stateprov));
04485       } else if (!strcasecmp(v->name, "country")) {
04486          ast_copy_string(country, v->value, sizeof(country));
04487       } else if (!strcasecmp(v->name, "email")) {
04488          ast_copy_string(email, v->value, sizeof(email));
04489       } else if (!strcasecmp(v->name, "phone")) {
04490          ast_copy_string(phone, v->value, sizeof(phone));
04491       } else if (!strcasecmp(v->name, "storehistory")) {
04492          global_storehistory = ast_true(v->value);
04493       } else if (!strcasecmp(v->name, "cachetime")) {
04494          if ((sscanf(v->value, "%d", &x) == 1)) {
04495             dundi_cache_time = x;
04496          } else {
04497             ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
04498                v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
04499          }
04500       }
04501       v = v->next;
04502    }
04503    AST_LIST_UNLOCK(&peers);
04504    mark_mappings();
04505    v = ast_variable_browse(cfg, "mappings");
04506    while(v) {
04507       build_mapping(v->name, v->value);
04508       v = v->next;
04509    }
04510    prune_mappings();
04511    mark_peers();
04512    cat = ast_category_browse(cfg, NULL);
04513    while(cat) {
04514       if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
04515          /* Entries */
04516          if (!dundi_str_to_eid(&testeid, cat))
04517             build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
04518          else if (!strcasecmp(cat, "*")) {
04519             build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel);
04520             any_peer = find_peer(NULL);
04521          } else
04522             ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
04523       }
04524       cat = ast_category_browse(cfg, cat);
04525    }
04526    prune_peers();
04527    ast_config_destroy(cfg);
04528    load_password();
04529    if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
04530       dundi_precache_full();
04531    return 0;
04532 }

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

Definition at line 2036 of file pbx_dundi.c.

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

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

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

Definition at line 2340 of file pbx_dundi.c.

References rescomp().

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

02341 {
02342    qsort(results, count, sizeof(results[0]), rescomp);
02343 }

static int start_network_thread ( void   )  [static]

Definition at line 2211 of file pbx_dundi.c.

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

02212 {
02213    ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
02214    ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
02215    return 0;
02216 }

static int str2tech ( char *  str  )  [static]

Definition at line 318 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

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

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

static int unload_module ( void   )  [static]

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

04535 {
04536    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid;
04537    ast_module_user_hangup_all();
04538 
04539    /* Stop all currently running threads */
04540    dundi_shutdown = 1;
04541    if (previous_netthreadid != AST_PTHREADT_NULL) {
04542       pthread_kill(previous_netthreadid, SIGURG);
04543       pthread_join(previous_netthreadid, NULL);
04544    }
04545    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04546       pthread_kill(previous_precachethreadid, SIGURG);
04547       pthread_join(previous_precachethreadid, NULL);
04548    }
04549 
04550    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04551    ast_unregister_switch(&dundi_switch);
04552    ast_custom_function_unregister(&dundi_function);
04553    close(netsocket);
04554    io_context_destroy(io);
04555    sched_context_destroy(sched);
04556 
04557    mark_mappings();
04558    prune_mappings();
04559    mark_peers();
04560    prune_peers();
04561 
04562    return 0;
04563 }

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3464 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, dr, and peers.

Referenced by dundi_lookup_internal().

03465 {
03466    AST_LIST_LOCK(&peers);
03467    AST_LIST_REMOVE(&requests, dr, list);
03468    AST_LIST_UNLOCK(&peers);
03469 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1287 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, and LOG_NOTICE.

Referenced by dundi_encrypt().

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


Variable Documentation

struct dundi_peer* any_peer [static]

Wildcard peer.

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

Definition at line 274 of file pbx_dundi.c.

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

int authdebug = 0 [static]

Definition at line 116 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2769 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

char country[80] [static]

Definition at line 128 of file pbx_dundi.c.

Referenced by ind_load_module().

char cursecret[80] [static]

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

int default_expiration = 60 [static]

Definition at line 122 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 124 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 119 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 118 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 136 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4366 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 117 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 115 of file pbx_dundi.c.

char email[80] [static]

Definition at line 129 of file pbx_dundi.c.

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

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

int global_autokilltimeout = 0 [static]

Definition at line 120 of file pbx_dundi.c.

dundi_eid global_eid [static]

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

struct io_context* io [static]

Definition at line 109 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 133 of file pbx_dundi.c.

Referenced by realtime_update_peer().

char locality[80] [static]

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

int netsocket = -1 [static]

Definition at line 111 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

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

char org[80] [static]

Definition at line 125 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

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

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

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

time_t rotatetime [static]

Definition at line 134 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 110 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 131 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 2733 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 2725 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 2737 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 2717 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 2729 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 2741 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 2721 of file pbx_dundi.c.

char stateprov[80] [static]

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

int tos = 0 [static]

Definition at line 114 of file pbx_dundi.c.


Generated on Mon Nov 24 15:34:47 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7