Fri Sep 25 19:28:41 2009

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"

Include dependency graph for pbx_dundi.c:

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 build_peer(), 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_peer(), 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 build_peer(), and 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 destroy_trans(), 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(), dundi_encrypt(), and handle_command_response().

#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 3953 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 handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 79 of file pbx_dundi.c.


Function Documentation

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3354 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03355 {
03356    struct dundi_transaction *trans;
03357 
03358    AST_LIST_LOCK(&peers);
03359    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03360       /* This will remove the transaction from the list */
03361       destroy_trans(trans, 0);
03362    }
03363    AST_LIST_UNLOCK(&peers);
03364 }

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

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

Referenced by handle_frame().

01958 {
01959    struct dundi_packet *pack;
01960 
01961    /* Ack transmitted packet corresponding to iseqno */
01962    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01963       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01964          destroy_packet(pack, 0);
01965          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01966             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01967             destroy_packets(&trans->lasttrans);
01968          }
01969          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01970          if (trans->autokillid > -1)
01971             ast_sched_del(sched, trans->autokillid);
01972          trans->autokillid = -1;
01973          return 1;
01974       }
01975    }
01976 
01977    return 0;
01978 }

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

Definition at line 3940 of file pbx_dundi.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

Referenced by build_peer().

03941 {
03942    struct permission *perm;
03943 
03944    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03945       return;
03946 
03947    strcpy(perm->name, s);
03948    perm->allow = allow;
03949 
03950    AST_LIST_INSERT_TAIL(permlist, perm, list);
03951 }

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

Definition at line 3311 of file pbx_dundi.c.

References dundi_peer::addr, AST_LIST_INSERT_HEAD, ast_log(), ast_strlen_zero(), create_transaction(), dundi_request::dcontext, dundi_eid_to_str(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, LOG_DEBUG, dundi_request::number, dundi_request::query_eid, and dundi_transaction::ttl.

Referenced by build_transactions().

03312 {
03313    struct dundi_transaction *trans;
03314    int x;
03315    char eid_str[20];
03316    char eid_str2[20];
03317 
03318    /* Ignore if not registered */
03319    if (!p->addr.sin_addr.s_addr)
03320       return 0;
03321    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03322       return 0;
03323    if (ast_strlen_zero(dr->number))
03324       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);
03325    else
03326       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);
03327    trans = create_transaction(p);
03328    if (!trans)
03329       return -1;
03330    trans->parent = dr;
03331    trans->ttl = ttl;
03332    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03333       trans->eids[x] = *avoid[x];
03334    trans->eidcount = x;
03335    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03336    
03337    return 0;
03338 }

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

Definition at line 1253 of file pbx_dundi.c.

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

Referenced by create_transaction(), and handle_command_response().

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

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

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03476 {
03477    /* Idea is that we're calculating a checksum which is independent of
03478       the order that the EID's are listed in */
03479    unsigned long acrc32 = 0;
03480    int x;
03481    for (x=0;avoid[x];x++) {
03482       /* Order doesn't matter */
03483       if (avoid[x+1]) {
03484          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03485       }
03486    }
03487    return acrc32;
03488 }

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

Definition at line 503 of file pbx_dundi.c.

References ast_random().

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

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

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

Definition at line 3955 of file pbx_dundi.c.

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

Referenced by set_config().

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

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

Definition at line 4108 of file pbx_dundi.c.

References dundi_peer::addr, append_permission(), ast_calloc, ast_gethostbyname(), AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), ast_sched_del(), ast_true(), DEFAULT_MAXMS, destroy_permissions(), do_register(), dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_MODEL_SYMMETRIC, DUNDI_PORT, dundi_str_to_eid(), dundi_peer::eid, hp, ast_variable::lineno, LOG_WARNING, ast_variable::name, ast_variable::next, peers, populate_addr(), qualify_peer(), and ast_variable::value.

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

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

Definition at line 2049 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02050 {
02051    unsigned char tmp[16];
02052    char *s;
02053    build_iv(tmp);
02054    secret[0] = '\0';
02055    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02056    /* Eliminate potential bad characters */
02057    while((s = strchr(secret, ';'))) *s = '+';
02058    while((s = strchr(secret, '/'))) *s = '+';
02059    while((s = strchr(secret, ':'))) *s = '+';
02060    while((s = strchr(secret, '@'))) *s = '+';
02061 }

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

References append_transaction(), ast_clear_flag_nonstd, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), cache_lookup(), dundi_request::crc32, dundi_request::dcontext, dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, dundi_request::expiration, has_permission(), dundi_request::hmd, LOG_DEBUG, and peers.

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

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

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

Definition at line 1201 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, key(), dundi_request::number, dundi_request::respcount, and dundi_request::root_eid.

Referenced by build_transactions().

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

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

Definition at line 1129 of file pbx_dundi.c.

References ast_clear_flag_nonstd, ast_copy_flags, ast_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(), dundi_result::eid, dundi_result::eid_str, dundi_result::expiration, ast_flags::flags, dundi_request::hmd, LOG_DEBUG, dundi_request::respcount, dundi_result::tech, tech2str(), dundi_result::techint, and dundi_result::weight.

Referenced by cache_lookup().

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

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

Definition at line 848 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

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

Definition at line 813 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3340 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03341 {
03342    struct dundi_transaction *trans;
03343 
03344    AST_LIST_LOCK(&peers);
03345    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03346       /* Orphan transaction from request */
03347       trans->parent = NULL;
03348       /* Send final cancel */
03349       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03350    }
03351    AST_LIST_UNLOCK(&peers);
03352 }

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

Definition at line 1452 of file pbx_dundi.c.

References aes_decrypt_key128(), aes_encrypt_key128(), ast_check_signature_bin, ast_decrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_eid_to_str(), dundi_peer::eid, key(), LOG_DEBUG, LOG_NOTICE, and option_debug.

Referenced by handle_command_response().

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

static void check_password ( void   )  [static]

Definition at line 2116 of file pbx_dundi.c.

References build_secret(), and save_secret().

Referenced by network_thread().

02117 {
02118    char oldsecret[80];
02119    time_t now;
02120    
02121    time(&now); 
02122 #if 0
02123    printf("%ld/%ld\n", now, rotatetime);
02124 #endif
02125    if ((now - rotatetime) >= 0) {
02126       /* Time to rotate keys */
02127       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02128       build_secret(cursecret, sizeof(cursecret));
02129       save_secret(cursecret, oldsecret);
02130    }
02131 }

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3461 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by dundi_lookup_internal().

03462 {
03463    struct dundi_request *cur;
03464 
03465    AST_LIST_LOCK(&peers);
03466    AST_LIST_TRAVERSE(&requests, cur, list) {
03467       if (cur == dr)
03468          break;
03469    }
03470    AST_LIST_UNLOCK(&peers);
03471    
03472    return cur ? 1 : 0;
03473 }

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

Definition at line 2308 of file pbx_dundi.c.

References complete_peer_helper().

02309 {
02310    return complete_peer_helper(line, word, pos, state, 3);
02311 }

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

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

02287 {
02288    int which=0, len;
02289    char *ret = NULL;
02290    struct dundi_peer *p;
02291    char eid_str[20];
02292 
02293    if (pos != rpos)
02294       return NULL;
02295    AST_LIST_LOCK(&peers);
02296    len = strlen(word);
02297    AST_LIST_TRAVERSE(&peers, p, list) {
02298       const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02299       if (!strncasecmp(word, s, len) && ++which > state) {
02300          ret = ast_strdup(s);
02301          break;
02302       }
02303    }
02304    AST_LIST_UNLOCK(&peers);
02305    return ret;
02306 }

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

Definition at line 2816 of file pbx_dundi.c.

References dundi_peer::addr, apply_peer(), ast_calloc, AST_LIST_INSERT_HEAD, ast_set_flag, dundi_transaction::autokillid, DUNDI_DEFAULT_RETRANS_TIMER, FLAG_SENDFULLKEY, FLAG_STOREHIST, get_trans_id(), dundi_transaction::retranstimer, dundi_transaction::start, and dundi_transaction::strans.

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

02817 {
02818    struct dundi_transaction *trans;
02819    int tid;
02820    
02821    /* Don't allow creation of transactions to non-registered peers */
02822    if (p && !p->addr.sin_addr.s_addr)
02823       return NULL;
02824    tid = get_trans_id();
02825    if (tid < 1)
02826       return NULL;
02827    trans = ast_calloc(1, sizeof(*trans));
02828    if (trans) {
02829       if (global_storehistory) {
02830          trans->start = ast_tvnow();
02831          ast_set_flag(trans, FLAG_STOREHIST);
02832       }
02833       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02834       trans->autokillid = -1;
02835       if (p) {
02836          apply_peer(trans, p);
02837          if (!p->sentfullkey)
02838             ast_set_flag(trans, FLAG_SENDFULLKEY);
02839       }
02840       trans->strans = tid;
02841       AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02842    }
02843    return trans;
02844 }

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

Definition at line 1344 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

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

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

Definition at line 1506 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, and AST_LIST_TRAVERSE.

Referenced by handle_command_response().

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 3905 of file pbx_dundi.c.

References free.

Referenced by prune_mappings().

03906 {
03907    free(map);
03908 }

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

Definition at line 2862 of file pbx_dundi.c.

References AST_LIST_REMOVE, ast_sched_del(), and free.

Referenced by ack_trans().

02863 {
02864    if (pack->parent)
02865       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02866    if (pack->retransid > -1)
02867       ast_sched_del(sched, pack->retransid);
02868    if (needfree)
02869       free(pack);
02870    else
02871       pack->retransid = -1;
02872 }

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

Definition at line 1945 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, ast_sched_del(), and free.

Referenced by ack_trans(), destroy_trans(), and handle_frame().

01946 {
01947    struct dundi_packet *pack;
01948    
01949    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01950       if (pack->retransid > -1)
01951          ast_sched_del(sched, pack->retransid);
01952       free(pack);
01953    }
01954 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 3892 of file pbx_dundi.c.

References ast_sched_del(), destroy_permissions(), destroy_trans(), and free.

Referenced by prune_peers().

03893 {
03894    if (peer->registerid > -1)
03895       ast_sched_del(sched, peer->registerid);
03896    if (peer->regtrans)
03897       destroy_trans(peer->regtrans, 0);
03898    if (peer->qualifyid > -1)
03899       ast_sched_del(sched, peer->qualifyid);
03900    destroy_permissions(&peer->permit);
03901    destroy_permissions(&peer->include);
03902    free(peer);
03903 }

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

Definition at line 3884 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by build_peer(), and destroy_peer().

03885 {
03886    struct permission *perm;
03887 
03888    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03889       free(perm);
03890 }

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

Definition at line 2874 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_sched_del(), ast_set_flag, ast_strlen_zero(), ast_test_flag, dundi_transaction::autokillid, destroy_packets(), dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_DEAD, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, free, LOG_NOTICE, peers, dundi_transaction::start, dundi_transaction::them_eid, and dundi_transaction::thread.

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

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3196 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03197 {
03198    struct dundi_transaction *trans;
03199    AST_LIST_LOCK(&peers);
03200    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03201       dundi_discover(trans);
03202    }
03203    AST_LIST_UNLOCK(&peers);
03204    return 0;
03205 }

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

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

03052 {
03053    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03054    char eid_str[20];
03055    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03056       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03057    trans->autokillid = -1;
03058    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03059    return 0;
03060 }

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

Definition at line 4051 of file pbx_dundi.c.

References qualify_peer().

Referenced by qualify_peer().

04052 {
04053    struct dundi_peer *peer = (struct dundi_peer *)data;
04054    peer->qualifyid = -1;
04055    qualify_peer(peer, 0);
04056    return 0;
04057 }

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

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

Referenced by build_peer().

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

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

Note:
Called with the peers list already locked

Definition at line 1278 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

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

Definition at line 374 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_command_response(), and 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 753 of file pbx_dundi.c.

References ast_calloc, ast_log(), ast_pthread_create, dundi_ies::called_context, 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_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_query_state::fluffy, free, LOG_DEBUG, LOG_WARNING, dundi_ies::reqeid, dundi_query_state::reqeid, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

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

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

Definition at line 1041 of file pbx_dundi.c.

References ast_calloc, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create, dundi_ies::called_context, dundi_query_state::called_context, dundi_ies::called_number, dundi_query_state::called_number, dundi_ies::cbypass, dundi_mapping::dcontext, dundi_query_state::directs, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_DPRESPONSE, dundi_eid_cmp(), dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_lookup_thread(), dundi_send(), dundi_ies::eid_direct, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_query_state::fluffy, free, LOG_DEBUG, LOG_WARNING, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.

Referenced by handle_command_response().

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

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

Definition at line 4300 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04301 {
04302    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04303 }

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, read]

Definition at line 1361 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

Referenced by discover_transactions().

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

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

Definition at line 2203 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02204 {
02205    if (argc != 2)
02206       return RESULT_SHOWUSAGE;
02207    dundidebug = 1;
02208    ast_cli(fd, "DUNDi Debugging Enabled\n");
02209    return RESULT_SUCCESS;
02210 }

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

Definition at line 2330 of file pbx_dundi.c.

References ast_cli(), context, dundi_flags2str(), dundi_lookup(), dundi_transaction::flags, RESULT_SHOWUSAGE, RESULT_SUCCESS, and sort_results().

02331 {
02332    int res;
02333    char tmp[256];
02334    char fs[80] = "";
02335    char *context;
02336    int x;
02337    int bypass = 0;
02338    struct dundi_result dr[MAX_RESULTS];
02339    struct timeval start;
02340    if ((argc < 3) || (argc > 4))
02341       return RESULT_SHOWUSAGE;
02342    if (argc > 3) {
02343       if (!strcasecmp(argv[3], "bypass"))
02344          bypass=1;
02345       else
02346          return RESULT_SHOWUSAGE;
02347    }
02348    ast_copy_string(tmp, argv[2], sizeof(tmp));
02349    context = strchr(tmp, '@');
02350    if (context) {
02351       *context = '\0';
02352       context++;
02353    }
02354    start = ast_tvnow();
02355    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02356    
02357    if (res < 0) 
02358       ast_cli(fd, "DUNDi lookup returned error.\n");
02359    else if (!res) 
02360       ast_cli(fd, "DUNDi lookup returned no results.\n");
02361    else
02362       sort_results(dr, res);
02363    for (x=0;x<res;x++) {
02364       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));
02365       ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02366    }
02367    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02368    return RESULT_SUCCESS;
02369 }

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

Definition at line 2371 of file pbx_dundi.c.

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

02372 {
02373    int res;
02374    char tmp[256];
02375    char *context;
02376    struct timeval start;
02377    if ((argc < 3) || (argc > 3))
02378       return RESULT_SHOWUSAGE;
02379    ast_copy_string(tmp, argv[2], sizeof(tmp));
02380    context = strchr(tmp, '@');
02381    if (context) {
02382       *context = '\0';
02383       context++;
02384    }
02385    start = ast_tvnow();
02386    res = dundi_precache(context, tmp);
02387    
02388    if (res < 0) 
02389       ast_cli(fd, "DUNDi precache returned error.\n");
02390    else if (!res) 
02391       ast_cli(fd, "DUNDi precache returned no error.\n");
02392    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02393    return RESULT_SUCCESS;
02394 }

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

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

02397 {
02398    int res;
02399    char tmp[256];
02400    char *context;
02401    dundi_eid eid;
02402    struct dundi_entity_info dei;
02403    if ((argc < 3) || (argc > 3))
02404       return RESULT_SHOWUSAGE;
02405    if (dundi_str_to_eid(&eid, argv[2])) {
02406       ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
02407       return RESULT_SHOWUSAGE;
02408    }
02409    ast_copy_string(tmp, argv[2], sizeof(tmp));
02410    context = strchr(tmp, '@');
02411    if (context) {
02412       *context = '\0';
02413       context++;
02414    }
02415    res = dundi_query_eid(&dei, context, eid);
02416    if (res < 0) 
02417       ast_cli(fd, "DUNDi Query EID returned error.\n");
02418    else if (!res) 
02419       ast_cli(fd, "DUNDi Query EID returned no results.\n");
02420    else {
02421       ast_cli(fd, "DUNDi Query EID succeeded:\n");
02422       ast_cli(fd, "Department:      %s\n", dei.orgunit);
02423       ast_cli(fd, "Organization:    %s\n", dei.org);
02424       ast_cli(fd, "City/Locality:   %s\n", dei.locality);
02425       ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
02426       ast_cli(fd, "Country:         %s\n", dei.country);
02427       ast_cli(fd, "E-mail:          %s\n", dei.email);
02428       ast_cli(fd, "Phone:           %s\n", dei.phone);
02429       ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
02430    }
02431    return RESULT_SUCCESS;
02432 }

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

Definition at line 2212 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02213 {
02214    if (argc != 3)
02215       return RESULT_SHOWUSAGE;
02216    global_storehistory = 1;
02217    ast_cli(fd, "DUNDi History Storage Enabled\n");
02218    return RESULT_SUCCESS;
02219 }

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

Definition at line 1385 of file pbx_dundi.c.

References ast_log(), ast_set_flag, ast_test_flag, dundi_ie_data::buf, 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_ie_data::pos, dundi_transaction::them_eid, update_key(), and dundi_transaction::us_eid.

Referenced by dundi_send().

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

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

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

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

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

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04296 {
04297    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04298 }

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

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

02222 {
02223    int stats = 0;
02224    if ((argc < 2) || (argc > 3))
02225       return RESULT_SHOWUSAGE;
02226    if (argc > 2) {
02227       if (!strcasecmp(argv[2], "stats"))
02228          stats = 1;
02229       else
02230          return RESULT_SHOWUSAGE;
02231    }
02232    if (stats) {
02233       /* Flush statistics */
02234       struct dundi_peer *p;
02235       int x;
02236       AST_LIST_LOCK(&peers);
02237       AST_LIST_TRAVERSE(&peers, p, list) {
02238          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02239             if (p->lookups[x])
02240                free(p->lookups[x]);
02241             p->lookups[x] = NULL;
02242             p->lookuptimes[x] = 0;
02243          }
02244          p->avgms = 0;
02245       }
02246       AST_LIST_UNLOCK(&peers);
02247    } else {
02248       ast_db_deltree("dundi/cache", NULL);
02249       ast_cli(fd, "DUNDi Cache Flushed\n");
02250    }
02251    return RESULT_SUCCESS;
02252 }

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

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

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

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

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

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

03063 {
03064    struct dundi_peer *p;
03065    if (!dundi_eid_cmp(eid, us)) {
03066       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03067       return;
03068    }
03069    AST_LIST_LOCK(&peers);
03070    AST_LIST_TRAVERSE(&peers, p, list) {
03071       if (!dundi_eid_cmp(&p->eid, eid)) {
03072          if (has_permission(&p->include, context))
03073             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03074          else
03075             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03076          break;
03077       }
03078    }
03079    if (!p)
03080       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03081    AST_LIST_UNLOCK(&peers);
03082 }

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

References DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_lookup_internal(), and dundi_hint_metadata::flags.

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

03593 {
03594    struct dundi_hint_metadata hmd;
03595    dundi_eid *avoid[1] = { NULL, };
03596    int direct[1] = { 0, };
03597    int expiration = dundi_cache_time;
03598    memset(&hmd, 0, sizeof(hmd));
03599    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03600    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03601 }

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 3490 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(), dundi_request::cbypass, check_request(), dundi_request::crc32, dundi_request::dcontext, discover_transactions(), dundi_request::dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_DEBUG, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, and unregister_request().

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

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

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

Definition at line 529 of file pbx_dundi.c.

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

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 602 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), dundi_query_state::directs, 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, dundi_result::expiration, dundi_hint_metadata::exten, FLAG_DEAD, dundi_transaction::flags, dundi_hint_metadata::flags, free, LOG_DEBUG, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, peers, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by dundi_answer_query().

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

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

Definition at line 4357 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04358 {
04359    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04360 }

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

Definition at line 2254 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02255 {
02256    if (argc != 3)
02257       return RESULT_SHOWUSAGE;
02258    dundidebug = 0;
02259    ast_cli(fd, "DUNDi Debugging Disabled\n");
02260    return RESULT_SUCCESS;
02261 }

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

Definition at line 2263 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02264 {
02265    if (argc != 4)
02266       return RESULT_SHOWUSAGE;
02267    global_storehistory = 0;
02268    ast_cli(fd, "DUNDi History Storage Disabled\n");
02269    return RESULT_SUCCESS;
02270 }

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

Pre-cache to push upstream peers.

Definition at line 3736 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03737 {
03738    dundi_eid *avoid[1] = { NULL, };
03739    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03740 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3639 of file pbx_dundi.c.

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

03640 {
03641    struct dundi_mapping *cur;
03642    struct ast_context *con;
03643    struct ast_exten *e;
03644 
03645    AST_LIST_TRAVERSE(&mappings, cur, list) {
03646       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03647       ast_lock_contexts();
03648       con = ast_walk_contexts(NULL);
03649       while (con) {
03650          if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
03651             /* Found the match, now queue them all up */
03652             ast_lock_context(con);
03653             e = ast_walk_context_extensions(con, NULL);
03654             while (e) {
03655                reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03656                e = ast_walk_context_extensions(con, e);
03657             }
03658             ast_unlock_context(con);
03659          }
03660          con = ast_walk_contexts(con);
03661       }
03662       ast_unlock_contexts();
03663    }
03664 }

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

Definition at line 3666 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(), dundi_request::dcontext, dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, dundi_request::expiration, dundi_request::hmd, LOG_DEBUG, LOG_NOTICE, dundi_request::maxcount, dundi_request::number, optimize_transactions(), peers, dundi_request::pfds, precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

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

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

Definition at line 666 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache().

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

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

Definition at line 889 of file pbx_dundi.c.

References dundi_ies::anscount, dundi_ies::answers, ast_calloc, ast_clear_flag_nonstd, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create, cache_save(), cache_save_hint(), dundi_query_state::called_context, dundi_ies::called_context, dundi_query_state::called_number, dundi_ies::called_number, dundi_ies::cbypass, dundi_answer::data, dundi_mapping::dcontext, dundi_request::dcontext, dundi_query_state::directs, dundi_request::dr, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_PRECACHERP, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_precache_thread(), dundi_send(), dundi_answer::eid, dundi_ies::eid_direct, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_ies::expiration, dundi_request::expiration, dundi_answer::flags, dundi_transaction::flags, dundi_hint_metadata::flags, dundi_query_state::fluffy, free, dundi_ies::hint, dundi_request::hmd, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, dundi_query_state::maps, dundi_request::maxcount, dundi_query_state::nocache, dundi_request::number, dundi_query_state::nummaps, dundi_request::pfds, dundi_answer::protocol, s, tech2str(), dundi_transaction::them_eid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, dundi_query_state::ttl, and dundi_answer::weight.

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

Referenced by query_transactions().

03175 {
03176    struct dundi_ie_data ied;
03177    int x;
03178    if (!trans->parent) {
03179       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03180       return -1;
03181    }
03182    memset(&ied, 0, sizeof(ied));
03183    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03184    if (!dundi_eid_zero(&trans->us_eid))
03185       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03186    for (x=0;x<trans->eidcount;x++)
03187       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03188    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03189    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03190    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03191    if (trans->autokilltimeout)
03192       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03193    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03194 }

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

Retrieve information on a specific EID.

Definition at line 3789 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03790 {
03791    dundi_eid *avoid[1] = { NULL, };
03792    struct dundi_hint_metadata hmd;
03793    memset(&hmd, 0, sizeof(hmd));
03794    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03795 }

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

References AST_LIST_EMPTY, ast_set_flag_nonstd, build_transactions(), dundi_request::dcontext, dundi_request::dei, DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, dundi_request::hmd, optimize_transactions(), dundi_request::pfds, dundi_request::query_eid, query_transactions(), dundi_request::respcount, and dundi_request::root_eid.

Referenced by dundi_query_eid(), and dundi_query_thread().

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

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

Definition at line 699 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, dundi_entity_info::country, 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, dundi_entity_info::email, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, free, dundi_entity_info::ipaddr, dundi_entity_info::locality, LOG_DEBUG, dundi_entity_info::org, dundi_entity_info::orgunit, peers, dundi_entity_info::phone, dundi_query_state::reqeid, dundi_entity_info::stateprov, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

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

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

Definition at line 378 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

02958 {
02959    struct dundi_packet *pack = (struct dundi_packet *)data;
02960    int res;
02961    AST_LIST_LOCK(&peers);
02962    if (pack->retrans < 1) {
02963       pack->retransid = -1;
02964       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
02965          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
02966             ast_inet_ntoa(pack->parent->addr.sin_addr), 
02967             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
02968       destroy_trans(pack->parent, 1);
02969       res = 0;
02970    } else {
02971       /* Decrement retransmission, try again */
02972       pack->retrans--;
02973       dundi_xmit(pack);
02974       res = 1;
02975    }
02976    AST_LIST_UNLOCK(&peers);
02977    return res;
02978 }

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

Definition at line 2980 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, 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_prop_precache(), dundi_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().

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

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

Definition at line 2601 of file pbx_dundi.c.

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

02602 {
02603    char eid_str[20];
02604    if (argc != 3)
02605       return RESULT_SHOWUSAGE;
02606    AST_LIST_LOCK(&peers);
02607    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02608    AST_LIST_UNLOCK(&peers);
02609    ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
02610    return RESULT_SUCCESS;
02611 }

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

Definition at line 2635 of file pbx_dundi.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), dundi_mapping::dcontext, dundi_mapping::dest, dundi_flags2str(), FORMAT, FORMAT2, dundi_mapping::lcontext, map, dundi_mapping::options, peers, RESULT_SHOWUSAGE, RESULT_SUCCESS, dundi_mapping::tech, tech2str(), and dundi_mapping::weight.

02636 {
02637 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02638 #define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
02639    struct dundi_mapping *map;
02640    char fs[256];
02641    if (argc != 3)
02642       return RESULT_SHOWUSAGE;
02643    AST_LIST_LOCK(&peers);
02644    ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02645    AST_LIST_TRAVERSE(&mappings, map, list) {
02646       ast_cli(fd, FORMAT, map->dcontext, map->weight, 
02647          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02648          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02649    }
02650    AST_LIST_UNLOCK(&peers);
02651    return RESULT_SUCCESS;
02652 #undef FORMAT
02653 #undef FORMAT2
02654 }

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

Definition at line 2434 of file pbx_dundi.c.

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

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

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

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

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

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

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

02657 {
02658 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02659 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02660    struct dundi_precache_queue *qe;
02661    int h,m,s;
02662    time_t now;
02663    
02664    if (argc != 3)
02665       return RESULT_SHOWUSAGE;
02666    time(&now);
02667    ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
02668    AST_LIST_LOCK(&pcq);
02669    AST_LIST_TRAVERSE(&pcq, qe, list) {
02670       s = qe->expiration - now;
02671       h = s / 3600;
02672       s = s % 3600;
02673       m = s / 60;
02674       s = s % 60;
02675       ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
02676    }
02677    AST_LIST_UNLOCK(&pcq);
02678    
02679    return RESULT_SUCCESS;
02680 #undef FORMAT
02681 #undef FORMAT2
02682 }

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

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

02614 {
02615 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02616 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02617    struct dundi_request *req;
02618    char eidstr[20];
02619    if (argc != 3)
02620       return RESULT_SHOWUSAGE;
02621    AST_LIST_LOCK(&peers);
02622    ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02623    AST_LIST_TRAVERSE(&requests, req, list) {
02624       ast_cli(fd, FORMAT, req->number, req->dcontext,
02625          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02626    }
02627    AST_LIST_UNLOCK(&peers);
02628    return RESULT_SUCCESS;
02629 #undef FORMAT
02630 #undef FORMAT2
02631 }

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

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

02583 {
02584 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02585 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02586    struct dundi_transaction *trans;
02587    if (argc != 3)
02588       return RESULT_SHOWUSAGE;
02589    AST_LIST_LOCK(&peers);
02590    ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02591    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02592       ast_cli(fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02593          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02594    }
02595    AST_LIST_UNLOCK(&peers);
02596    return RESULT_SUCCESS;
02597 #undef FORMAT
02598 #undef FORMAT2
02599 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

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

02847 {
02848    int res;
02849    if (dundidebug)
02850       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02851    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02852    if (res < 0) {
02853       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02854          ast_inet_ntoa(pack->parent->addr.sin_addr),
02855          ntohs(pack->parent->addr.sin_port), strerror(errno));
02856    }
02857    if (res > 0)
02858       res = 0;
02859    return res;
02860 }

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

Definition at line 3797 of file pbx_dundi.c.

References ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), ast_test_flag, context, DUNDI_FLAG_EXISTS, dundi_lookup(), LOG_WARNING, and sort_results().

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

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

Definition at line 1328 of file pbx_dundi.c.

References aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 485 of file pbx_dundi.c.

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

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

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

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

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

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1536 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, apply_peer(), dundi_transaction::aseqno, ast_calloc, ast_clear_flag, ast_clear_flag_nonstd, ast_db_put(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_sched_add(), ast_sched_del(), ast_set_flag, ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verbose(), cache_save(), cache_save_hint(), dundi_ies::called_context, dundi_ies::called_number, dundi_ies::cause, check_key(), dundi_hdr::cmdresp, dundi_hint::data, dundi_answer::data, dundi_transaction::dcx, deep_copy_peer(), do_register_expire(), dundi_ack(), dundi_answer_entity(), dundi_answer_query(), DUNDI_CAUSE_GENERAL, DUNDI_CAUSE_NOAUTH, DUNDI_COMMAND_CANCEL, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_ENCREJ, DUNDI_COMMAND_ENCRYPT, DUNDI_COMMAND_INVALID, DUNDI_COMMAND_NULL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_COMMAND_UNKNOWN, dundi_decrypt(), dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_byte(), dundi_ie_append_cause(), dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_raw(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_EXPIRATION, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, DUNDI_IE_UNKNOWN, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_showframe(), dundi_transaction::ecx, dundi_answer::eid, dundi_peer::eid, dundi_ies::eids, dundi_ies::encblock, dundi_encblock::encdata, dundi_ies::enclen, dundi_ies::encsharedkey, dundi_ies::encsig, dundi_ies::expiration, find_peer(), FLAG_ENCRYPT, FLAG_SENDFULLKEY, dundi_answer::flags, dundi_transaction::flags, has_permission(), dundi_ies::hint, dundi_hdr::ies, inaddrcmp(), dundi_transaction::iseqno, dundi_encblock::iv, dundi_ies::keycrc32, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, MAX_PACKET_SIZE, option_verbose, dundi_transaction::oseqno, dundi_hdr::oseqno, peers, dundi_answer::protocol, dundi_ies::q_country, dundi_ies::q_dept, dundi_ies::q_email, dundi_ies::q_ipaddr, dundi_ies::q_locality, dundi_ies::q_org, dundi_ies::q_phone, dundi_ies::q_stateprov, qualify_peer(), reset_transaction(), tech2str(), dundi_transaction::them_eid, dundi_transaction::us_eid, VERBOSE_PREFIX_3, and dundi_answer::weight.

Referenced by handle_frame().

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

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

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

01981 {
01982    struct dundi_transaction *trans;
01983    trans = find_transaction(h, sin);
01984    if (!trans) {
01985       dundi_reject(h, sin);
01986       return 0;
01987    }
01988    /* Got a transaction, see where this header fits in */
01989    if (h->oseqno == trans->iseqno) {
01990       /* Just what we were looking for...  Anything but ack increments iseqno */
01991       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
01992          /* If final, we're done */
01993          destroy_trans(trans, 0);
01994          return 0;
01995       }
01996       if (h->cmdresp != DUNDI_COMMAND_ACK) {
01997          trans->oiseqno = trans->iseqno;
01998          trans->iseqno++;
01999          handle_command_response(trans, h, datalen, 0);
02000       }
02001       if (trans->aseqno != trans->iseqno) {
02002          dundi_ack(trans, h->cmdresp & 0x80);
02003          trans->aseqno = trans->iseqno;
02004       }
02005       /* Delete any saved last transmissions */
02006       destroy_packets(&trans->lasttrans);
02007       if (h->cmdresp & 0x80) {
02008          /* Final -- destroy now */
02009          destroy_trans(trans, 0);
02010       }
02011    } else if (h->oseqno == trans->oiseqno) {
02012       /* Last incoming sequence number -- send ACK without processing */
02013       dundi_ack(trans, 0);
02014    } else {
02015       /* Out of window -- simply drop */
02016       ast_log(LOG_DEBUG, "Dropping packet out of window!\n");
02017    }
02018    return 0;
02019 }

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 4568 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(), dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, LOG_WARNING, option_verbose, sched_context_create(), set_config(), start_network_thread(), and VERBOSE_PREFIX_2.

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

static void load_password ( void   )  [static]

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

02078 {
02079    char *current=NULL;
02080    char *last=NULL;
02081    char tmp[256];
02082    time_t expired;
02083    
02084    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02085    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02086       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02087       current = strchr(tmp, ';');
02088       if (!current)
02089          current = tmp;
02090       else {
02091          *current = '\0';
02092          current++;
02093       };
02094       if ((time(NULL) - expired) < 0) {
02095          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02096             expired = time(NULL) + DUNDI_SECRET_TIME;
02097       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02098          last = current;
02099          current = NULL;
02100       } else {
02101          last = NULL;
02102          current = NULL;
02103       }
02104    }
02105    if (current) {
02106       /* Current key is still valid, just setup rotatation properly */
02107       ast_copy_string(cursecret, current, sizeof(cursecret));
02108       rotatetime = expired;
02109    } else {
02110       /* Current key is out of date, rotate or eliminate all together */
02111       build_secret(cursecret, sizeof(cursecret));
02112       save_secret(cursecret, last);
02113    }
02114 }

static void mark_mappings ( void   )  [static]

Definition at line 3873 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_mapping::dead, map, and peers.

Referenced by set_config(), and unload_module().

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

static void mark_peers ( void   )  [static]

Definition at line 3863 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by set_config(), and unload_module().

03864 {
03865    struct dundi_peer *peer;
03866    AST_LIST_LOCK(&peers);
03867    AST_LIST_TRAVERSE(&peers, peer, list) {
03868       peer->dead = 1;
03869    }
03870    AST_LIST_UNLOCK(&peers);
03871 }

static char* model2str ( int  model  )  [static]

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

02273 {
02274    switch(model) {
02275    case DUNDI_MODEL_INBOUND:
02276       return "Inbound";
02277    case DUNDI_MODEL_OUTBOUND:
02278       return "Outbound";
02279    case DUNDI_MODEL_SYMMETRIC:
02280       return "Symmetric";
02281    default:
02282       return "Unknown";
02283    }
02284 }

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

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

02134 {
02135    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
02136       from the network, and queue them for delivery to the channels */
02137    int res;
02138    /* Establish I/O callback for socket read */
02139    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02140    
02141    while (!dundi_shutdown) {
02142       res = ast_sched_wait(sched);
02143       if ((res > 1000) || (res < 0))
02144          res = 1000;
02145       res = ast_io_wait(io, res);
02146       if (res >= 0) {
02147          AST_LIST_LOCK(&peers);
02148          ast_sched_runq(sched);
02149          AST_LIST_UNLOCK(&peers);
02150       }
02151       check_password();
02152    }
02153 
02154    netthreadid = AST_PTHREADT_NULL;
02155    
02156    return NULL;
02157 }

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

Definition at line 3255 of file pbx_dundi.c.

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

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

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

Definition at line 4084 of file pbx_dundi.c.

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

Referenced by build_peer().

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

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

Definition at line 3108 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, destroy_trans(), do_autokill(), DUNDI_COMMAND_PRECACHERQ, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), DUNDI_IE_ANSWER, dundi_ie_append_answer(), dundi_ie_append_eid(), dundi_ie_append_hint(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID, DUNDI_IE_EXPIRATION, DUNDI_IE_HINT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_lookup_internal(), dundi_lookup_local(), dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, dundi_result::expiration, dundi_hint_metadata::exten, dundi_hint_metadata::flags, dundi_transaction::flags, LOG_WARNING, dundi_transaction::them_eid, dundi_transaction::ttl, dundi_transaction::us_eid, and dundi_result::weight.

Referenced by precache_transactions().

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

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

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

Referenced by dundi_precache_internal().

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

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

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

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

static void prune_mappings ( void   )  [static]

Definition at line 3925 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

03926 {
03927    struct dundi_mapping *map;
03928 
03929    AST_LIST_LOCK(&peers);
03930    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
03931       if (map->dead) {
03932          AST_LIST_REMOVE_CURRENT(&mappings, list);
03933          destroy_map(map);
03934       }
03935    }
03936    AST_LIST_TRAVERSE_SAFE_END
03937    AST_LIST_UNLOCK(&peers);
03938 }

static void prune_peers ( void   )  [static]

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

03911 {
03912    struct dundi_peer *peer;
03913 
03914    AST_LIST_LOCK(&peers);
03915    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
03916       if (peer->dead) {
03917          AST_LIST_REMOVE_CURRENT(&peers, list);
03918          destroy_peer(peer);
03919       }
03920    }
03921    AST_LIST_TRAVERSE_SAFE_END
03922    AST_LIST_UNLOCK(&peers);
03923 }

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

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

Referenced by build_peer(), do_qualify(), and handle_command_response().

04060 {
04061    int when;
04062    if (peer->qualifyid > -1)
04063       ast_sched_del(sched, peer->qualifyid);
04064    peer->qualifyid = -1;
04065    if (peer->qualtrans)
04066       destroy_trans(peer->qualtrans, 0);
04067    peer->qualtrans = NULL;
04068    if (peer->maxms > 0) {
04069       when = 60000;
04070       if (peer->lastms < 0)
04071          when = 10000;
04072       if (schedonly)
04073          when = 5000;
04074       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04075       if (!schedonly)
04076          peer->qualtrans = create_transaction(peer);
04077       if (peer->qualtrans) {
04078          peer->qualtx = ast_tvnow();
04079          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04080          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04081       }
04082    }
04083 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3242 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

03243 {
03244    struct dundi_transaction *trans;
03245 
03246    AST_LIST_LOCK(&peers);
03247    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03248       dundi_query(trans);
03249    }
03250    AST_LIST_UNLOCK(&peers);
03251 
03252    return 0;
03253 }

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

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

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

static int reload ( void   )  [static]

Definition at line 4561 of file pbx_dundi.c.

References set_config().

04562 {
04563    struct sockaddr_in sin;
04564    set_config("dundi.conf",&sin);
04565    return 0;
04566 }

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

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

03604 {
03605    int len;
03606    struct dundi_precache_queue *qe, *prev;
03607 
03608    AST_LIST_LOCK(&pcq);
03609    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03610       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03611          AST_LIST_REMOVE_CURRENT(&pcq, list);
03612          break;
03613       }
03614    }
03615    AST_LIST_TRAVERSE_SAFE_END
03616    if (!qe) {
03617       len = sizeof(*qe);
03618       len += strlen(number) + 1;
03619       len += strlen(context) + 1;
03620       if (!(qe = ast_calloc(1, len))) {
03621          AST_LIST_UNLOCK(&pcq);
03622          return;
03623       }
03624       strcpy(qe->number, number);
03625       qe->context = qe->number + strlen(number) + 1;
03626       strcpy(qe->context, context);
03627    }
03628    time(&qe->expiration);
03629    qe->expiration += expiration;
03630    if ((prev = AST_LIST_FIRST(&pcq))) {
03631       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03632          prev = AST_LIST_NEXT(prev, list);
03633       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03634    } else
03635       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03636    AST_LIST_UNLOCK(&pcq);
03637 }

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

Definition at line 2313 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02314 {
02315    const struct dundi_result *resa, *resb;
02316    resa = a;
02317    resb = b;
02318    if (resa->weight < resb->weight)
02319       return -1;
02320    if (resa->weight > resb->weight)
02321       return 1;
02322    return 0;
02323 }

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, LOG_DEBUG, LOG_NOTICE, 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'\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) {
00434             struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
00435             memcpy(
00436                &(global_eid.eid),
00437                sdp->sdl_data + sdp->sdl_nlen, 6);
00438             ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifap->ifa_name);
00439             freeifaddrs(ifap);
00440             return;
00441          }
00442       }
00443       freeifaddrs(ifap);
00444    }
00445 #endif
00446 #endif
00447    ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID  You will have to set it manually.\n");
00448 }

static int reset_transaction ( struct dundi_transaction trans  )  [static]

Definition at line 469 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 2064 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02065 {
02066    char tmp[256];
02067    if (oldkey)
02068       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02069    else
02070       snprintf(tmp, sizeof(tmp), "%s", newkey);
02071    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02072    ast_db_put(secretpath, "secret", tmp);
02073    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02074    ast_db_put(secretpath, "secretexpiry", tmp);
02075 }

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

Definition at line 4372 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(), find_peer(), format, hp, IPTOS_MINCOST, ast_variable::lineno, load_password(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mark_mappings(), mark_peers(), ast_variable::name, ast_variable::next, peers, prune_mappings(), prune_peers(), reset_global_eid(), and ast_variable::value.

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

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

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

02022 {
02023    struct sockaddr_in sin;
02024    int res;
02025    struct dundi_hdr *h;
02026    char buf[MAX_PACKET_SIZE];
02027    socklen_t len;
02028    len = sizeof(sin);
02029    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
02030    if (res < 0) {
02031       if (errno != ECONNREFUSED)
02032          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
02033       return 1;
02034    }
02035    if (res < sizeof(struct dundi_hdr)) {
02036       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
02037       return 1;
02038    }
02039    buf[res] = '\0';
02040    h = (struct dundi_hdr *)buf;
02041    if (dundidebug)
02042       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
02043    AST_LIST_LOCK(&peers);
02044    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
02045    AST_LIST_UNLOCK(&peers);
02046    return 1;
02047 }

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

Definition at line 2325 of file pbx_dundi.c.

References rescomp().

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

02326 {
02327    qsort(results, count, sizeof(results[0]), rescomp);
02328 }

static int start_network_thread ( void   )  [static]

Definition at line 2196 of file pbx_dundi.c.

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

02197 {
02198    ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
02199    ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
02200    return 0;
02201 }

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 4530 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(), io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), and sched_context_destroy().

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

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3454 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and peers.

Referenced by dundi_lookup_internal().

03455 {
03456    AST_LIST_LOCK(&peers);
03457    AST_LIST_REMOVE(&requests, dr, list);
03458    AST_LIST_UNLOCK(&peers);
03459 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1289 of file pbx_dundi.c.

References aes_decrypt_key128(), aes_encrypt_key128(), ast_encrypt_bin, ast_key_get, AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), ast_sign_bin, build_iv(), dundi_eid_to_str(), dundi_peer::eid, key(), and LOG_NOTICE.

Referenced by dundi_encrypt().

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


Variable Documentation

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

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

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.

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

int global_autokilltimeout = 0 [static]

Definition at line 120 of file pbx_dundi.c.

Definition at line 121 of file pbx_dundi.c.

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 2730 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 2688 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 2697 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 2736 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 2742 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 2718 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 2710 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 2722 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 2702 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 2714 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 2726 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 2706 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 2692 of file pbx_dundi.c.

int tos = 0 [static]

Definition at line 114 of file pbx_dundi.c.


Generated on Fri Sep 25 19:28:41 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5