Fri Aug 24 02:27:08 2007

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 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 (void *data)
static int do_qualify (void *data)
static int do_register (void *data)
static int do_register_expire (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 (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 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 99 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 84 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 85 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 86 of file pbx_dundi.c.

Referenced by model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 104 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10

Keep times of last 10 lookups

Definition at line 89 of file pbx_dundi.c.

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

#define FLAG_DEAD   (1 << 1)

Transaction is dead

Definition at line 92 of file pbx_dundi.c.

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

#define FLAG_ENCRYPT   (1 << 4)

Transaction is encrypted wiht ECX/DCX

Definition at line 95 of file pbx_dundi.c.

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

#define FLAG_FINAL   (1 << 2)

Transaction has final message sent

Definition at line 93 of file pbx_dundi.c.

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

#define FLAG_ISQUAL   (1 << 3)

Transaction is a qualification

Definition at line 94 of file pbx_dundi.c.

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

#define FLAG_ISREG   (1 << 0)

Transaction is register request

Definition at line 91 of file pbx_dundi.c.

Referenced by destroy_trans(), and do_register().

#define FLAG_SENDFULLKEY   (1 << 5)

Send full key on transaction

Definition at line 96 of file pbx_dundi.c.

Referenced by create_transaction(), and dundi_encrypt().

#define FLAG_STOREHIST   (1 << 6)

Record historic performance

Definition at line 97 of file pbx_dundi.c.

Referenced by create_transaction(), and destroy_trans().

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

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

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

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

#define FORMAT   "%-20.20s %-15.15s %s %-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 108 of file pbx_dundi.c.

#define KEY_OUT   0

Definition at line 107 of file pbx_dundi.c.

#define MAX_OPTS   128

Definition at line 3895 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 82 of file pbx_dundi.c.

Referenced by socket_read().

#define MAX_RESULTS   64

Definition at line 80 of file pbx_dundi.c.

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


Function Documentation

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3296 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03297 {
03298    struct dundi_transaction *trans;
03299 
03300    AST_LIST_LOCK(&peers);
03301    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03302       /* This will remove the transaction from the list */
03303       destroy_trans(trans, 0);
03304    }
03305    AST_LIST_UNLOCK(&peers);
03306 }

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

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

01901 {
01902    struct dundi_packet *pack;
01903 
01904    /* Ack transmitted packet corresponding to iseqno */
01905    AST_LIST_TRAVERSE(&trans->packets, pack, list) {
01906       if ((pack->h->oseqno + 1) % 255 == iseqno) {
01907          destroy_packet(pack, 0);
01908          if (!AST_LIST_EMPTY(&trans->lasttrans)) {
01909             ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
01910             destroy_packets(&trans->lasttrans);
01911          }
01912          AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
01913          if (trans->autokillid > -1)
01914             ast_sched_del(sched, trans->autokillid);
01915          trans->autokillid = -1;
01916          return 1;
01917       }
01918    }
01919 
01920    return 0;
01921 }

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

Definition at line 3882 of file pbx_dundi.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

03883 {
03884    struct permission *perm;
03885 
03886    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03887       return;
03888 
03889    strcpy(perm->name, s);
03890    perm->allow = allow;
03891 
03892    AST_LIST_INSERT_TAIL(permlist, perm, list);
03893 }

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

Definition at line 3253 of file pbx_dundi.c.

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

Referenced by build_transactions().

03254 {
03255    struct dundi_transaction *trans;
03256    int x;
03257    char eid_str[20];
03258    char eid_str2[20];
03259 
03260    /* Ignore if not registered */
03261    if (!p->addr.sin_addr.s_addr)
03262       return 0;
03263    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03264       return 0;
03265    if (ast_strlen_zero(dr->number))
03266       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);
03267    else
03268       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);
03269    trans = create_transaction(p);
03270    if (!trans)
03271       return -1;
03272    trans->parent = dr;
03273    trans->ttl = ttl;
03274    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03275       trans->eids[x] = *avoid[x];
03276    trans->eidcount = x;
03277    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03278    
03279    return 0;
03280 }

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

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

Referenced by create_transaction().

01244 {
01245    if (!trans->addr.sin_addr.s_addr)
01246       memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
01247    trans->us_eid = p->us_eid;
01248    trans->them_eid = p->eid;
01249    /* Enable encryption if appropriate */
01250    if (!ast_strlen_zero(p->inkey))
01251       ast_set_flag(trans, FLAG_ENCRYPT);  
01252    if (p->maxms) {
01253       trans->autokilltimeout = p->maxms;
01254       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01255       if (p->lastms > 1) {
01256          trans->retranstimer = p->lastms * 2;
01257          /* Keep it from being silly */
01258          if (trans->retranstimer < 150)
01259             trans->retranstimer = 150;
01260       }
01261       if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
01262          trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
01263    } else
01264       trans->autokilltimeout = global_autokilltimeout;
01265 }

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

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03418 {
03419    /* Idea is that we're calculating a checksum which is independent of
03420       the order that the EID's are listed in */
03421    unsigned long acrc32 = 0;
03422    int x;
03423    for (x=0;avoid[x];x++) {
03424       /* Order doesn't matter */
03425       if (avoid[x+1]) {
03426          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03427       }
03428    }
03429    return acrc32;
03430 }

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

Definition at line 493 of file pbx_dundi.c.

References ast_random().

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

00494 {
00495    /* XXX Would be nice to be more random XXX */
00496    unsigned int *fluffy;
00497    int x;
00498    fluffy = (unsigned int *)(iv);
00499    for (x=0;x<4;x++)
00500       fluffy[x] = ast_random();
00501 }

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

Definition at line 3897 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, ast_strlen_zero(), DUNDI_FLAG_COMMERCIAL, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MOBILE, DUNDI_FLAG_NOCOMUNSOLICIT, DUNDI_FLAG_NOUNSOLICITED, DUNDI_FLAG_RESIDENTIAL, LOG_WARNING, map, MAX_OPTS, str2tech(), and t.

Referenced by set_config().

03898 {
03899    char *t, *fields[MAX_OPTS];
03900    struct dundi_mapping *map;
03901    int x;
03902    int y;
03903 
03904    t = ast_strdupa(value);
03905       
03906    AST_LIST_TRAVERSE(&mappings, map, list) {
03907       /* Find a double match */
03908       if (!strcasecmp(map->dcontext, name) && 
03909          (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 
03910            (!value[strlen(map->lcontext)] || 
03911             (value[strlen(map->lcontext)] == ','))))
03912          break;
03913    }
03914    if (!map) {
03915       if (!(map = ast_calloc(1, sizeof(*map))))
03916          return;
03917       AST_LIST_INSERT_HEAD(&mappings, map, list);
03918       map->dead = 1;
03919    }
03920    map->options = 0;
03921    memset(fields, 0, sizeof(fields));
03922    x = 0;
03923    while (t && x < MAX_OPTS) {
03924       fields[x++] = t;
03925       t = strchr(t, ',');
03926       if (t) {
03927          *t = '\0';
03928          t++;
03929       }
03930    } /* Russell was here, arrrr! */
03931    if ((x == 1) && ast_strlen_zero(fields[0])) {
03932       /* Placeholder mapping */
03933       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
03934       map->dead = 0;
03935    } else if (x >= 4) {
03936       ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
03937       ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
03938       if ((sscanf(fields[1], "%d", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) {
03939          ast_copy_string(map->dest, fields[3], sizeof(map->dest));
03940          if ((map->tech = str2tech(fields[2]))) {
03941             map->dead = 0;
03942          }
03943       } else {
03944          ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
03945       }
03946       for (y = 4;y < x; y++) {
03947          if (!strcasecmp(fields[y], "nounsolicited"))
03948             map->options |= DUNDI_FLAG_NOUNSOLICITED;
03949          else if (!strcasecmp(fields[y], "nocomunsolicit"))
03950             map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
03951          else if (!strcasecmp(fields[y], "residential"))
03952             map->options |= DUNDI_FLAG_RESIDENTIAL;
03953          else if (!strcasecmp(fields[y], "commercial"))
03954             map->options |= DUNDI_FLAG_COMMERCIAL;
03955          else if (!strcasecmp(fields[y], "mobile"))
03956             map->options |= DUNDI_FLAG_MOBILE;
03957          else if (!strcasecmp(fields[y], "nopartial"))
03958             map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
03959          else
03960             ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
03961       }
03962    } else 
03963       ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
03964 }

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

Definition at line 4051 of file pbx_dundi.c.

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

04052 {
04053    struct dundi_peer *peer;
04054    struct ast_hostent he;
04055    struct hostent *hp;
04056    dundi_eid testeid;
04057    int needregister=0;
04058    char eid_str[20];
04059 
04060    AST_LIST_LOCK(&peers);
04061    AST_LIST_TRAVERSE(&peers, peer, list) {
04062       if (!dundi_eid_cmp(&peer->eid, eid)) { 
04063          break;
04064       }
04065    }
04066    if (!peer) {
04067       /* Add us into the list */
04068       if (!(peer = ast_calloc(1, sizeof(*peer)))) {
04069          AST_LIST_UNLOCK(&peers);
04070          return;
04071       }
04072       peer->registerid = -1;
04073       peer->registerexpire = -1;
04074       peer->qualifyid = -1;
04075       peer->addr.sin_family = AF_INET;
04076       peer->addr.sin_port = htons(DUNDI_PORT);
04077       populate_addr(peer, eid);
04078       AST_LIST_INSERT_HEAD(&peers, peer, list);
04079    }
04080    peer->dead = 0;
04081    peer->eid = *eid;
04082    peer->us_eid = global_eid;
04083    destroy_permissions(&peer->permit);
04084    destroy_permissions(&peer->include);
04085    if (peer->registerid > -1)
04086       ast_sched_del(sched, peer->registerid);
04087    peer->registerid = -1;
04088    for (; v; v = v->next) {
04089       if (!strcasecmp(v->name, "inkey")) {
04090          ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
04091       } else if (!strcasecmp(v->name, "outkey")) {
04092          ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
04093       } else if (!strcasecmp(v->name, "host")) {
04094          if (!strcasecmp(v->value, "dynamic")) {
04095             peer->dynamic = 1;
04096          } else {
04097             hp = ast_gethostbyname(v->value, &he);
04098             if (hp) {
04099                memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
04100                peer->dynamic = 0;
04101             } else {
04102                ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
04103                peer->dead = 1;
04104             }
04105          }
04106       } else if (!strcasecmp(v->name, "ustothem")) {
04107          if (!dundi_str_to_eid(&testeid, v->value))
04108             peer->us_eid = testeid;
04109          else
04110             ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
04111       } else if (!strcasecmp(v->name, "include")) {
04112          append_permission(&peer->include, v->value, 1);
04113       } else if (!strcasecmp(v->name, "permit")) {
04114          append_permission(&peer->permit, v->value, 1);
04115       } else if (!strcasecmp(v->name, "noinclude")) {
04116          append_permission(&peer->include, v->value, 0);
04117       } else if (!strcasecmp(v->name, "deny")) {
04118          append_permission(&peer->permit, v->value, 0);
04119       } else if (!strcasecmp(v->name, "register")) {
04120          needregister = ast_true(v->value);
04121       } else if (!strcasecmp(v->name, "order")) {
04122          if (!strcasecmp(v->value, "primary"))
04123             peer->order = 0;
04124          else if (!strcasecmp(v->value, "secondary"))
04125             peer->order = 1;
04126          else if (!strcasecmp(v->value, "tertiary"))
04127             peer->order = 2;
04128          else if (!strcasecmp(v->value, "quartiary"))
04129             peer->order = 3;
04130          else {
04131             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);
04132          }
04133       } else if (!strcasecmp(v->name, "qualify")) {
04134          if (!strcasecmp(v->value, "no")) {
04135             peer->maxms = 0;
04136          } else if (!strcasecmp(v->value, "yes")) {
04137             peer->maxms = DEFAULT_MAXMS;
04138          } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
04139             ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 
04140                dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
04141             peer->maxms = 0;
04142          }
04143       } else if (!strcasecmp(v->name, "model")) {
04144          if (!strcasecmp(v->value, "inbound"))
04145             peer->model = DUNDI_MODEL_INBOUND;
04146          else if (!strcasecmp(v->value, "outbound")) 
04147             peer->model = DUNDI_MODEL_OUTBOUND;
04148          else if (!strcasecmp(v->value, "symmetric"))
04149             peer->model = DUNDI_MODEL_SYMMETRIC;
04150          else if (!strcasecmp(v->value, "none"))
04151             peer->model = 0;
04152          else {
04153             ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04154                v->value, v->lineno);
04155          }
04156       } else if (!strcasecmp(v->name, "precache")) {
04157          if (!strcasecmp(v->value, "inbound"))
04158             peer->pcmodel = DUNDI_MODEL_INBOUND;
04159          else if (!strcasecmp(v->value, "outbound")) 
04160             peer->pcmodel = DUNDI_MODEL_OUTBOUND;
04161          else if (!strcasecmp(v->value, "symmetric"))
04162             peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
04163          else if (!strcasecmp(v->value, "none"))
04164             peer->pcmodel = 0;
04165          else {
04166             ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 
04167                v->value, v->lineno);
04168          }
04169       }
04170    }
04171    (*globalpcmode) |= peer->pcmodel;
04172    if (!peer->model && !peer->pcmodel) {
04173       ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 
04174          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04175       peer->dead = 1;
04176    } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04177       ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 
04178          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04179       peer->dead = 1;
04180    } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04181       ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 
04182          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04183       peer->dead = 1;
04184    } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
04185       ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 
04186          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04187    } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
04188       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", 
04189          dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
04190    } else { 
04191       if (needregister) {
04192          peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
04193       }
04194       qualify_peer(peer, 1);
04195    }
04196    AST_LIST_UNLOCK(&peers);
04197 }

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

Definition at line 1992 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

01993 {
01994    unsigned char tmp[16];
01995    char *s;
01996    build_iv(tmp);
01997    secret[0] = '\0';
01998    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
01999    /* Eliminate potential bad characters */
02000    while((s = strchr(secret, ';'))) *s = '+';
02001    while((s = strchr(secret, '/'))) *s = '+';
02002    while((s = strchr(secret, ':'))) *s = '+';
02003    while((s = strchr(secret, '@'))) *s = '+';
02004 }

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

References append_transaction(), ast_clear_flag_nonstd, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), cache_lookup(), dr, dundi_eid_cmp(), dundi_eid_to_str(), dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, has_permission(), LOG_DEBUG, and peers.

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

03309 {
03310    struct dundi_peer *p;
03311    int x;
03312    int res;
03313    int pass;
03314    int allowconnect;
03315    char eid_str[20];
03316    AST_LIST_LOCK(&peers);
03317    AST_LIST_TRAVERSE(&peers, p, list) {
03318       if (modeselect == 1) {
03319          /* Send the precache to push upstreams only! */
03320          pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
03321          allowconnect = 1;
03322       } else {
03323          /* Normal lookup / EID query */
03324          pass = has_permission(&p->include, dr->dcontext);
03325          allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
03326       }
03327       if (skip) {
03328          if (!dundi_eid_cmp(skip, &p->eid))
03329             pass = 0;
03330       }
03331       if (pass) {
03332          if (p->order <= order) {
03333             /* Check order first, then check cache, regardless of
03334                omissions, this gets us more likely to not have an
03335                affected answer. */
03336             if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
03337                res = 0;
03338                /* Make sure we haven't already seen it and that it won't
03339                   affect our answer */
03340                for (x=0;avoid[x];x++) {
03341                   if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
03342                      /* If not a direct connection, it affects our answer */
03343                      if (directs && !directs[x]) 
03344                         ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
03345                      break;
03346                   }
03347                }
03348                /* Make sure we can ask */
03349                if (allowconnect) {
03350                   if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
03351                      /* Check for a matching or 0 cache entry */
03352                      append_transaction(dr, p, ttl, avoid);
03353                   } else
03354                      ast_log(LOG_DEBUG, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
03355                }
03356             }
03357             *foundcache |= res;
03358          } else if (!*skipped || (p->order < *skipped))
03359             *skipped = p->order;
03360       }
03361    }
03362    AST_LIST_UNLOCK(&peers);
03363 }

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

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

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

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

Definition at line 1119 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, dundi_mapping::tech, tech2str(), dundi_result::techint, timeout, and dundi_result::weight.

Referenced by cache_lookup().

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

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

Definition at line 838 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, timeout, and dundi_result::weight.

Referenced by handle_command_response().

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

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

Definition at line 803 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, dundi_request::root_eid, and timeout.

Referenced by handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3282 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03283 {
03284    struct dundi_transaction *trans;
03285 
03286    AST_LIST_LOCK(&peers);
03287    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03288       /* Orphan transaction from request */
03289       trans->parent = NULL;
03290       /* Send final cancel */
03291       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03292    }
03293    AST_LIST_UNLOCK(&peers);
03294 }

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

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

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

static void check_password ( void   )  [static]

Definition at line 2059 of file pbx_dundi.c.

References build_secret(), cursecret, rotatetime, and save_secret().

Referenced by network_thread().

02060 {
02061    char oldsecret[80];
02062    time_t now;
02063    
02064    time(&now); 
02065 #if 0
02066    printf("%ld/%ld\n", now, rotatetime);
02067 #endif
02068    if ((now - rotatetime) >= 0) {
02069       /* Time to rotate keys */
02070       ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
02071       build_secret(cursecret, sizeof(cursecret));
02072       save_secret(cursecret, oldsecret);
02073    }
02074 }

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3403 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03404 {
03405    struct dundi_request *cur;
03406 
03407    AST_LIST_LOCK(&peers);
03408    AST_LIST_TRAVERSE(&requests, cur, list) {
03409       if (cur == dr)
03410          break;
03411    }
03412    AST_LIST_UNLOCK(&peers);
03413    
03414    return cur ? 1 : 0;
03415 }

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

Definition at line 2249 of file pbx_dundi.c.

References complete_peer_helper().

02250 {
02251    return complete_peer_helper(line, word, pos, state, 3);
02252 }

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

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

02230 {
02231    int which=0, len;
02232    char *ret = NULL;
02233    struct dundi_peer *p;
02234    char eid_str[20];
02235 
02236    if (pos != rpos)
02237       return NULL;
02238    AST_LIST_LOCK(&peers);
02239    len = strlen(word);
02240    AST_LIST_TRAVERSE(&peers, p, list) {
02241       const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
02242       if (!strncasecmp(word, s, len) && ++which > state)
02243          ret = ast_strdup(s);
02244    }
02245    AST_LIST_UNLOCK(&peers);
02246    return ret;
02247 }

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

Definition at line 2757 of file pbx_dundi.c.

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

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

02758 {
02759    struct dundi_transaction *trans;
02760    int tid;
02761    
02762    /* Don't allow creation of transactions to non-registered peers */
02763    if (p && !p->addr.sin_addr.s_addr)
02764       return NULL;
02765    tid = get_trans_id();
02766    if (tid < 1)
02767       return NULL;
02768    trans = ast_calloc(1, sizeof(*trans));
02769    if (trans) {
02770       if (global_storehistory) {
02771          trans->start = ast_tvnow();
02772          ast_set_flag(trans, FLAG_STOREHIST);
02773       }
02774       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
02775       trans->autokillid = -1;
02776       if (p) {
02777          apply_peer(trans, p);
02778          if (!p->sentfullkey)
02779             ast_set_flag(trans, FLAG_SENDFULLKEY);
02780       }
02781       trans->strans = tid;
02782       AST_LIST_INSERT_HEAD(&alltrans, trans, all);
02783    }
02784    return trans;
02785 }

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

Definition at line 1334 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

01335 {
01336    unsigned char lastblock[16];
01337    int x;
01338    memcpy(lastblock, iv, sizeof(lastblock));
01339    while(len > 0) {
01340       aes_decrypt(src, dst, dcx);
01341       for (x=0;x<16;x++)
01342          dst[x] ^= lastblock[x];
01343       memcpy(lastblock, src, sizeof(lastblock));
01344       dst += 16;
01345       src += 16;
01346       len -= 16;
01347    }
01348    return 0;
01349 }

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 3847 of file pbx_dundi.c.

References free, and map.

Referenced by prune_mappings().

03848 {
03849    free(map);
03850 }

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

Definition at line 2803 of file pbx_dundi.c.

References AST_LIST_REMOVE, ast_sched_del(), and free.

Referenced by ack_trans().

02804 {
02805    if (pack->parent)
02806       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02807    if (pack->retransid > -1)
02808       ast_sched_del(sched, pack->retransid);
02809    if (needfree)
02810       free(pack);
02811    else
02812       pack->retransid = -1;
02813 }

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

Definition at line 1888 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, ast_sched_del(), and free.

Referenced by ack_trans(), and handle_frame().

01889 {
01890    struct dundi_packet *pack;
01891    
01892    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01893       if (pack->retransid > -1)
01894          ast_sched_del(sched, pack->retransid);
01895       free(pack);
01896    }
01897 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 3834 of file pbx_dundi.c.

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

Referenced by prune_peers().

03835 {
03836    if (peer->registerid > -1)
03837       ast_sched_del(sched, peer->registerid);
03838    if (peer->regtrans)
03839       destroy_trans(peer->regtrans, 0);
03840    if (peer->qualifyid > -1)
03841       ast_sched_del(sched, peer->qualifyid);
03842    destroy_permissions(&peer->permit);
03843    destroy_permissions(&peer->include);
03844    free(peer);
03845 }

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

Definition at line 3826 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by build_peer(), and destroy_peer().

03827 {
03828    struct permission *perm;
03829 
03830    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03831       free(perm);
03832 }

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

Definition at line 2815 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_log(), ast_malloc, ast_strlen_zero(), ast_test_flag, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_TIMING_HISTORY, dundi_peer::eid, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, free, LOG_NOTICE, peers, dundi_transaction::start, and dundi_transaction::them_eid.

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

02816 {
02817    struct dundi_peer *peer;
02818    int ms;
02819    int x;
02820    int cnt;
02821    char eid_str[20];
02822    if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
02823       AST_LIST_TRAVERSE(&peers, peer, list) {
02824          if (peer->regtrans == trans)
02825             peer->regtrans = NULL;
02826          if (peer->qualtrans == trans) {
02827             if (fromtimeout) {
02828                if (peer->lastms > -1)
02829                   ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02830                peer->lastms = -1;
02831             } else {
02832                ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
02833                if (ms < 1)
02834                   ms = 1;
02835                if (ms < peer->maxms) {
02836                   if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
02837                      ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02838                } else if (peer->lastms < peer->maxms) {
02839                   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);
02840                }
02841                peer->lastms = ms;
02842             }
02843             peer->qualtrans = NULL;
02844          }
02845          if (ast_test_flag(trans, FLAG_STOREHIST)) {
02846             if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
02847                if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
02848                   peer->avgms = 0;
02849                   cnt = 0;
02850                   if (peer->lookups[DUNDI_TIMING_HISTORY-1])
02851                      free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
02852                   for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
02853                      peer->lookuptimes[x] = peer->lookuptimes[x-1];
02854                      peer->lookups[x] = peer->lookups[x-1];
02855                      if (peer->lookups[x]) {
02856                         peer->avgms += peer->lookuptimes[x];
02857                         cnt++;
02858                      }
02859                   }
02860                   peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
02861                   peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
02862                   if (peer->lookups[0]) {
02863                      sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
02864                      peer->avgms += peer->lookuptimes[0];
02865                      cnt++;
02866                   }
02867                   if (cnt)
02868                      peer->avgms /= cnt;
02869                }
02870             }
02871          }
02872       }
02873    }
02874    if (trans->parent) {
02875       /* Unlink from parent if appropriate */
02876       AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
02877       if (AST_LIST_EMPTY(&trans->parent->trans)) {
02878          /* Wake up sleeper */
02879          if (trans->parent->pfds[1] > -1) {
02880             write(trans->parent->pfds[1], "killa!", 6);
02881          }
02882       }
02883    }
02884    /* Unlink from all trans */
02885    AST_LIST_REMOVE(&alltrans, trans, all);
02886    destroy_packets(&trans->packets);
02887    destroy_packets(&trans->lasttrans);
02888    if (trans->autokillid > -1)
02889       ast_sched_del(sched, trans->autokillid);
02890    trans->autokillid = -1;
02891    if (trans->thread) {
02892       /* If used by a thread, mark as dead and be done */
02893       ast_set_flag(trans, FLAG_DEAD);
02894    } else
02895       free(trans);
02896 }

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3138 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03139 {
03140    struct dundi_transaction *trans;
03141    AST_LIST_LOCK(&peers);
03142    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03143       dundi_discover(trans);
03144    }
03145    AST_LIST_UNLOCK(&peers);
03146    return 0;
03147 }

static int do_autokill ( void *  data  )  [static]

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

02994 {
02995    struct dundi_transaction *trans = data;
02996    char eid_str[20];
02997    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
02998       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
02999    trans->autokillid = -1;
03000    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03001    return 0;
03002 }

static int do_qualify ( void *  data  )  [static]

Definition at line 3993 of file pbx_dundi.c.

References qualify_peer().

Referenced by qualify_peer().

03994 {
03995    struct dundi_peer *peer;
03996    peer = data;
03997    peer->qualifyid = -1;
03998    qualify_peer(peer, 0);
03999    return 0;
04000 }

static int do_register ( void *  data  )  [static]

Definition at line 3967 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), default_expiration, 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.

03968 {
03969    struct dundi_ie_data ied;
03970    struct dundi_peer *peer = data;
03971    char eid_str[20];
03972    char eid_str2[20];
03973    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));
03974    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
03975    /* Destroy old transaction if there is one */
03976    if (peer->regtrans)
03977       destroy_trans(peer->regtrans, 0);
03978    peer->regtrans = create_transaction(peer);
03979    if (peer->regtrans) {
03980       ast_set_flag(peer->regtrans, FLAG_ISREG);
03981       memset(&ied, 0, sizeof(ied));
03982       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03983       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
03984       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
03985       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
03986       
03987    } else
03988       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));
03989 
03990    return 0;
03991 }

static int do_register_expire ( void *  data  )  [static]

Note:
Called with the peers list already locked

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

01269 {
01270    struct dundi_peer *peer = data;
01271    char eid_str[20];
01272    ast_log(LOG_DEBUG, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
01273    peer->registerexpire = -1;
01274    peer->lastms = 0;
01275    memset(&peer->addr, 0, sizeof(peer->addr));
01276    return 0;
01277 }

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

Definition at line 367 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_frame().

00368 {
00369    return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00370 }

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

Definition at line 743 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 1031 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04244 {
04245    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04246 }

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

Definition at line 271 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

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

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

Definition at line 1351 of file pbx_dundi.c.

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

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

03027 {
03028    struct dundi_ie_data ied;
03029    int x;
03030    if (!trans->parent) {
03031       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03032       return -1;
03033    }
03034    memset(&ied, 0, sizeof(ied));
03035    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03036    if (!dundi_eid_zero(&trans->us_eid))
03037       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03038    for (x=0;x<trans->eidcount;x++)
03039       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03040    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03041    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03042    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03043    if (trans->parent->cbypass)
03044       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03045    if (trans->autokilltimeout)
03046       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03047    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03048 }

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

Definition at line 2146 of file pbx_dundi.c.

References ast_cli(), dundidebug, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02147 {
02148    if (argc != 2)
02149       return RESULT_SHOWUSAGE;
02150    dundidebug = 1;
02151    ast_cli(fd, "DUNDi Debugging Enabled\n");
02152    return RESULT_SUCCESS;
02153 }

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

Definition at line 2271 of file pbx_dundi.c.

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

02272 {
02273    int res;
02274    char tmp[256];
02275    char fs[80] = "";
02276    char *context;
02277    int x;
02278    int bypass = 0;
02279    struct dundi_result dr[MAX_RESULTS];
02280    struct timeval start;
02281    if ((argc < 3) || (argc > 4))
02282       return RESULT_SHOWUSAGE;
02283    if (argc > 3) {
02284       if (!strcasecmp(argv[3], "bypass"))
02285          bypass=1;
02286       else
02287          return RESULT_SHOWUSAGE;
02288    }
02289    ast_copy_string(tmp, argv[2], sizeof(tmp));
02290    context = strchr(tmp, '@');
02291    if (context) {
02292       *context = '\0';
02293       context++;
02294    }
02295    start = ast_tvnow();
02296    res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
02297    
02298    if (res < 0) 
02299       ast_cli(fd, "DUNDi lookup returned error.\n");
02300    else if (!res) 
02301       ast_cli(fd, "DUNDi lookup returned no results.\n");
02302    else
02303       sort_results(dr, res);
02304    for (x=0;x<res;x++) {
02305       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));
02306       ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
02307    }
02308    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02309    return RESULT_SUCCESS;
02310 }

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

Definition at line 2312 of file pbx_dundi.c.

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

02313 {
02314    int res;
02315    char tmp[256];
02316    char *context;
02317    struct timeval start;
02318    if ((argc < 3) || (argc > 3))
02319       return RESULT_SHOWUSAGE;
02320    ast_copy_string(tmp, argv[2], sizeof(tmp));
02321    context = strchr(tmp, '@');
02322    if (context) {
02323       *context = '\0';
02324       context++;
02325    }
02326    start = ast_tvnow();
02327    res = dundi_precache(context, tmp);
02328    
02329    if (res < 0) 
02330       ast_cli(fd, "DUNDi precache returned error.\n");
02331    else if (!res) 
02332       ast_cli(fd, "DUNDi precache returned no error.\n");
02333    ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
02334    return RESULT_SUCCESS;
02335 }

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

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

02338 {
02339    int res;
02340    char tmp[256];
02341    char *context;
02342    dundi_eid eid;
02343    struct dundi_entity_info dei;
02344    if ((argc < 3) || (argc > 3))
02345       return RESULT_SHOWUSAGE;
02346    if (dundi_str_to_eid(&eid, argv[2])) {
02347       ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]);
02348       return RESULT_SHOWUSAGE;
02349    }
02350    ast_copy_string(tmp, argv[2], sizeof(tmp));
02351    context = strchr(tmp, '@');
02352    if (context) {
02353       *context = '\0';
02354       context++;
02355    }
02356    res = dundi_query_eid(&dei, context, eid);
02357    if (res < 0) 
02358       ast_cli(fd, "DUNDi Query EID returned error.\n");
02359    else if (!res) 
02360       ast_cli(fd, "DUNDi Query EID returned no results.\n");
02361    else {
02362       ast_cli(fd, "DUNDi Query EID succeeded:\n");
02363       ast_cli(fd, "Department:      %s\n", dei.orgunit);
02364       ast_cli(fd, "Organization:    %s\n", dei.org);
02365       ast_cli(fd, "City/Locality:   %s\n", dei.locality);
02366       ast_cli(fd, "State/Province:  %s\n", dei.stateprov);
02367       ast_cli(fd, "Country:         %s\n", dei.country);
02368       ast_cli(fd, "E-mail:          %s\n", dei.email);
02369       ast_cli(fd, "Phone:           %s\n", dei.phone);
02370       ast_cli(fd, "IP Address:      %s\n", dei.ipaddr);
02371    }
02372    return RESULT_SUCCESS;
02373 }

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

Definition at line 2155 of file pbx_dundi.c.

References ast_cli(), global_storehistory, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02156 {
02157    if (argc != 3)
02158       return RESULT_SHOWUSAGE;
02159    global_storehistory = 1;
02160    ast_cli(fd, "DUNDi History Storage Enabled\n");
02161    return RESULT_SUCCESS;
02162 }

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

Definition at line 1375 of file pbx_dundi.c.

References ast_log(), ast_set_flag, ast_test_flag, build_iv(), dundi_transaction::dcx, DUNDI_COMMAND_ENCRYPT, dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_int(), dundi_ie_append_raw(), DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_KEYCRC32, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, dundi_transaction::ecx, encrypt_memcpy(), find_peer(), FLAG_SENDFULLKEY, len, LOG_DEBUG, LOG_NOTICE, dundi_transaction::them_eid, update_key(), and dundi_transaction::us_eid.

Referenced by dundi_send().

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

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

Definition at line 277 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

Definition at line 4248 of file pbx_dundi.c.

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

04249 {
04250    struct dundi_result results[MAX_RESULTS];
04251    int res;
04252    int x=0;
04253    char req[1024];
04254    struct ast_app *dial;
04255    
04256    if (!strncasecmp(context, "macro-", 6)) {
04257       if (!chan) {   
04258          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04259          return -1;
04260       }
04261       /* If done as a macro, use macro extension */
04262       if (!strcasecmp(exten, "s")) {
04263          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04264          if (ast_strlen_zero(exten))
04265             exten = chan->macroexten;
04266          if (ast_strlen_zero(exten))
04267             exten = chan->exten;
04268          if (ast_strlen_zero(exten)) { 
04269             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04270             return -1;
04271          }
04272       }
04273       if (ast_strlen_zero(data))
04274          data = "e164";
04275    } else {
04276       if (ast_strlen_zero(data))
04277          data = context;
04278    }
04279    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04280    if (res > 0) {
04281       sort_results(results, res);
04282       for (x=0;x<res;x++) {
04283          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04284             if (!--priority)
04285                break;
04286          }
04287       }
04288    }
04289    if (x < res) {
04290       /* Got a hit! */
04291       snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
04292       dial = pbx_findapp("Dial");
04293       if (dial)
04294          res = pbx_exec(chan, dial, req);
04295    } else
04296       res = -1;
04297    return res;
04298 }

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04239 {
04240    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04241 }

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

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

02165 {
02166    int stats = 0;
02167    if ((argc < 2) || (argc > 3))
02168       return RESULT_SHOWUSAGE;
02169    if (argc > 2) {
02170       if (!strcasecmp(argv[2], "stats"))
02171          stats = 1;
02172       else
02173          return RESULT_SHOWUSAGE;
02174    }
02175    if (stats) {
02176       /* Flush statistics */
02177       struct dundi_peer *p;
02178       int x;
02179       AST_LIST_LOCK(&peers);
02180       AST_LIST_TRAVERSE(&peers, p, list) {
02181          for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02182             if (p->lookups[x])
02183                free(p->lookups[x]);
02184             p->lookups[x] = NULL;
02185             p->lookuptimes[x] = 0;
02186          }
02187          p->avgms = 0;
02188       }
02189       AST_LIST_UNLOCK(&peers);
02190    } else {
02191       ast_db_deltree("dundi/cache", NULL);
02192       ast_cli(fd, "DUNDi Cache Flushed\n");
02193    }
02194    return RESULT_SUCCESS;
02195 }

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

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

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

04200 {
04201    struct dundi_result results[MAX_RESULTS];
04202    int res;
04203    int x;
04204    int found = 0;
04205    if (!strncasecmp(context, "macro-", 6)) {
04206       if (!chan) {   
04207          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04208          return -1;
04209       }
04210       /* If done as a macro, use macro extension */
04211       if (!strcasecmp(exten, "s")) {
04212          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04213          if (ast_strlen_zero(exten))
04214             exten = chan->macroexten;
04215          if (ast_strlen_zero(exten))
04216             exten = chan->exten;
04217          if (ast_strlen_zero(exten)) { 
04218             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04219             return -1;
04220          }
04221       }
04222       if (ast_strlen_zero(data))
04223          data = "e164";
04224    } else {
04225       if (ast_strlen_zero(data))
04226          data = context;
04227    }
04228    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04229    for (x=0;x<res;x++) {
04230       if (ast_test_flag(results + x, flag))
04231          found++;
04232    }
04233    if (found >= priority)
04234       return 1;
04235    return 0;
04236 }

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

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

03005 {
03006    struct dundi_peer *p;
03007    if (!dundi_eid_cmp(eid, us)) {
03008       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03009       return;
03010    }
03011    AST_LIST_LOCK(&peers);
03012    AST_LIST_TRAVERSE(&peers, p, list) {
03013       if (!dundi_eid_cmp(&p->eid, eid)) {
03014          if (has_permission(&p->include, context))
03015             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03016          else
03017             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03018          break;
03019       }
03020    }
03021    if (!p)
03022       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03023    AST_LIST_UNLOCK(&peers);
03024 }

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

References dundi_cache_time, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_lookup_internal(), dundi_ttl, and result.

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

03535 {
03536    struct dundi_hint_metadata hmd;
03537    dundi_eid *avoid[1] = { NULL, };
03538    int direct[1] = { 0, };
03539    int expiration = dundi_cache_time;
03540    memset(&hmd, 0, sizeof(hmd));
03541    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03542    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03543 }

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

References ast_channel::_softhangup, abort_request(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), check_request(), discover_transactions(), dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, LOG_DEBUG, LOG_WARNING, optimize_transactions(), register_request(), result, dundi_request::root_eid, and unregister_request().

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

03433 {
03434    int res;
03435    struct dundi_request dr, *pending;
03436    dundi_eid *rooteid=NULL;
03437    int x;
03438    int ttlms;
03439    int ms;
03440    int foundcache;
03441    int skipped=0;
03442    int order=0;
03443    char eid_str[20];
03444    struct timeval start;
03445    
03446    /* Don't do anthing for a hungup channel */
03447    if (chan && chan->_softhangup)
03448       return 0;
03449 
03450    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03451 
03452    for (x=0;avoid[x];x++)
03453       rooteid = avoid[x];
03454    /* Now perform real check */
03455    memset(&dr, 0, sizeof(dr));
03456    if (pipe(dr.pfds)) {
03457       ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
03458       return -1;
03459    }
03460    dr.dr = result;
03461    dr.hmd = hmd;
03462    dr.maxcount = maxret;
03463    dr.expiration = *expiration;
03464    dr.cbypass = cbypass;
03465    dr.crc32 = avoid_crc32(avoid);
03466    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03467    ast_copy_string(dr.number, number, sizeof(dr.number));
03468    if (rooteid)
03469       dr.root_eid = *rooteid;
03470    res = register_request(&dr, &pending);
03471    if (res) {
03472       /* Already a request */
03473       if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
03474          /* This is on behalf of someone else.  Go ahead and close this out since
03475             they'll get their answer anyway. */
03476          ast_log(LOG_DEBUG, "Oooh, duplicate request for '%s@%s' for '%s'\n",
03477             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
03478          close(dr.pfds[0]);
03479          close(dr.pfds[1]);
03480          return -2;
03481       } else {
03482          /* Wait for the cache to populate */
03483          ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n",
03484             dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
03485          start = ast_tvnow();
03486          while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03487             /* XXX Would be nice to have a way to poll/select here XXX */
03488             /* XXX this is a busy wait loop!!! */
03489             usleep(1);
03490          }
03491          /* Continue on as normal, our cache should kick in */
03492       }
03493    }
03494    /* Create transactions */
03495    do {
03496       order = skipped;
03497       skipped = 0;
03498       foundcache = 0;
03499       build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
03500    } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
03501    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03502       do this earlier because we didn't know if we were going to have transactions
03503       or not. */
03504    if (!ttl) {
03505       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03506       abort_request(&dr);
03507       unregister_request(&dr);
03508       close(dr.pfds[0]);
03509       close(dr.pfds[1]);
03510       return 0;
03511    }
03512       
03513    /* Optimize transactions */
03514    optimize_transactions(&dr, order);
03515    /* Actually perform transactions */
03516    discover_transactions(&dr);
03517    /* Wait for transaction to come back */
03518    start = ast_tvnow();
03519    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
03520       ms = 100;
03521       ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03522    }
03523    if (chan && chan->_softhangup)
03524       ast_log(LOG_DEBUG, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
03525    cancel_request(&dr);
03526    unregister_request(&dr);
03527    res = dr.respcount;
03528    *expiration = dr.expiration;
03529    close(dr.pfds[0]);
03530    close(dr.pfds[1]);
03531    return res;
03532 }

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

References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_exists_extension(), AST_FLAGS_ALL, ast_ignore_pattern(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_HEAD, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_var_delete(), dr, dundi_eid_to_str(), DUNDI_FLAG_CANMATCH, DUNDI_FLAG_EXISTS, DUNDI_FLAG_IGNOREPAT, DUNDI_FLAG_INTERNAL_NOPARTIAL, DUNDI_FLAG_MATCHMORE, DUNDI_HINT_DONT_ASK, dundi_transaction::flags, map, pbx_substitute_variables_varshead(), tech2str(), and dundi_transaction::us_eid.

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 592 of file pbx_dundi.c.

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

Referenced by dundi_answer_query().

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

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

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

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

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

Definition at line 2197 of file pbx_dundi.c.

References ast_cli(), dundidebug, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02198 {
02199    if (argc != 3)
02200       return RESULT_SHOWUSAGE;
02201    dundidebug = 0;
02202    ast_cli(fd, "DUNDi Debugging Disabled\n");
02203    return RESULT_SUCCESS;
02204 }

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

Definition at line 2206 of file pbx_dundi.c.

References ast_cli(), global_storehistory, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02207 {
02208    if (argc != 4)
02209       return RESULT_SHOWUSAGE;
02210    global_storehistory = 0;
02211    ast_cli(fd, "DUNDi History Storage Disabled\n");
02212    return RESULT_SUCCESS;
02213 }

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

Pre-cache to push upstream peers.

Definition at line 3678 of file pbx_dundi.c.

References dundi_precache_internal(), and dundi_ttl.

Referenced by dundi_do_precache(), and process_precache().

03679 {
03680    dundi_eid *avoid[1] = { NULL, };
03681    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03682 }

static void dundi_precache_full ( void   )  [static]

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

03582 {
03583    struct dundi_mapping *cur;
03584    struct ast_context *con;
03585    struct ast_exten *e;
03586 
03587    AST_LIST_TRAVERSE(&mappings, cur, list) {
03588       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03589       ast_lock_contexts();
03590       con = ast_walk_contexts(NULL);
03591       while (con) {
03592          if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
03593             /* Found the match, now queue them all up */
03594             ast_lock_context(con);
03595             e = ast_walk_context_extensions(con, NULL);
03596             while (e) {
03597                reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03598                e = ast_walk_context_extensions(con, e);
03599             }
03600             ast_unlock_context(con);
03601          }
03602          con = ast_walk_contexts(con);
03603       }
03604       ast_unlock_contexts();
03605    }
03606 }

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

Definition at line 3608 of file pbx_dundi.c.

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

Referenced by dundi_precache(), and dundi_precache_thread().

03609 {
03610    struct dundi_request dr;
03611    struct dundi_hint_metadata hmd;
03612    struct dundi_result dr2[MAX_RESULTS];
03613    struct timeval start;
03614    struct dundi_mapping *maps = NULL, *cur;
03615    int nummaps = 0;
03616    int foundanswers;
03617    int foundcache, skipped, ttlms, ms;
03618    if (!context)
03619       context = "e164";
03620    ast_log(LOG_DEBUG, "Precache internal (%s@%s)!\n", number, context);
03621 
03622    AST_LIST_LOCK(&peers);
03623    AST_LIST_TRAVERSE(&mappings, cur, list) {
03624       if (!strcasecmp(cur->dcontext, context))
03625          nummaps++;
03626    }
03627    if (nummaps) {
03628       maps = alloca(nummaps * sizeof(*maps));
03629       nummaps = 0;
03630       if (maps) {
03631          AST_LIST_TRAVERSE(&mappings, cur, list) {
03632             if (!strcasecmp(cur->dcontext, context))
03633                maps[nummaps++] = *cur;
03634          }
03635       }
03636    }
03637    AST_LIST_UNLOCK(&peers);
03638    if (!nummaps || !maps)
03639       return -1;
03640    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03641    memset(&dr2, 0, sizeof(dr2));
03642    memset(&dr, 0, sizeof(dr));
03643    memset(&hmd, 0, sizeof(hmd));
03644    dr.dr = dr2;
03645    ast_copy_string(dr.number, number, sizeof(dr.number));
03646    ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
03647    dr.maxcount = MAX_RESULTS;
03648    dr.expiration = dundi_cache_time;
03649    dr.hmd = &hmd;
03650    dr.pfds[0] = dr.pfds[1] = -1;
03651    pipe(dr.pfds);
03652    build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
03653    optimize_transactions(&dr, 0);
03654    foundanswers = 0;
03655    precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
03656    if (foundanswers) {
03657       if (dr.expiration > 0) 
03658          reschedule_precache(dr.number, dr.dcontext, dr.expiration);
03659       else
03660          ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
03661    }
03662    start = ast_tvnow();
03663    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
03664       if (dr.pfds[0] > -1) {
03665          ms = 100;
03666          ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
03667       } else
03668          usleep(1);
03669    }
03670    cancel_request(&dr);
03671    if (dr.pfds[0] > -1) {
03672       close(dr.pfds[0]);
03673       close(dr.pfds[1]);
03674    }
03675    return 0;
03676 }

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

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

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

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

Definition at line 879 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

03117 {
03118    struct dundi_ie_data ied;
03119    int x;
03120    if (!trans->parent) {
03121       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03122       return -1;
03123    }
03124    memset(&ied, 0, sizeof(ied));
03125    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03126    if (!dundi_eid_zero(&trans->us_eid))
03127       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03128    for (x=0;x<trans->eidcount;x++)
03129       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03130    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03131    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03132    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03133    if (trans->autokilltimeout)
03134       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03135    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03136 }

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

Retrieve information on a specific EID.

Definition at line 3731 of file pbx_dundi.c.

References dundi_query_eid_internal(), and dundi_ttl.

Referenced by dundi_do_query().

03732 {
03733    dundi_eid *avoid[1] = { NULL, };
03734    struct dundi_hint_metadata hmd;
03735    memset(&hmd, 0, sizeof(hmd));
03736    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03737 }

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

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

Referenced by dundi_query_eid(), and dundi_query_thread().

03685 {
03686    int res;
03687    struct dundi_request dr;
03688    dundi_eid *rooteid=NULL;
03689    int x;
03690    int ttlms;
03691    int skipped=0;
03692    int foundcache=0;
03693    struct timeval start;
03694    
03695    ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
03696 
03697    for (x=0;avoid[x];x++)
03698       rooteid = avoid[x];
03699    /* Now perform real check */
03700    memset(&dr, 0, sizeof(dr));
03701    dr.hmd = hmd;
03702    dr.dei = dei;
03703    dr.pfds[0] = dr.pfds[1] = -1;
03704    ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
03705    memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
03706    if (rooteid)
03707       dr.root_eid = *rooteid;
03708    /* Create transactions */
03709    build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
03710 
03711    /* If no TTL, abort and return 0 now after setting TTL expired hint.  Couldn't
03712       do this earlier because we didn't know if we were going to have transactions
03713       or not. */
03714    if (!ttl) {
03715       ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
03716       return 0;
03717    }
03718       
03719    /* Optimize transactions */
03720    optimize_transactions(&dr, 9999);
03721    /* Actually perform transactions */
03722    query_transactions(&dr);
03723    /* Wait for transaction to come back */
03724    start = ast_tvnow();
03725    while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
03726       usleep(1);
03727    res = dr.respcount;
03728    return res;
03729 }

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

Definition at line 689 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, FLAG_DEAD, free, LOG_DEBUG, peers, dundi_query_state::reqeid, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

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

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

Definition at line 371 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

static int dundi_rexmit ( void *  data  )  [static]

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

02899 {
02900    struct dundi_packet *pack;
02901    int res;
02902    AST_LIST_LOCK(&peers);
02903    pack = data;
02904    if (pack->retrans < 1) {
02905       pack->retransid = -1;
02906       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
02907          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
02908             ast_inet_ntoa(pack->parent->addr.sin_addr), 
02909             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
02910       destroy_trans(pack->parent, 1);
02911       res = 0;
02912    } else {
02913       /* Decrement retransmission, try again */
02914       pack->retrans--;
02915       dundi_xmit(pack);
02916       res = 1;
02917    }
02918    AST_LIST_UNLOCK(&peers);
02919    return res;
02920 }

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

Definition at line 2922 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(), dundidebug, 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_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().

02923 {
02924    struct dundi_packet *pack;
02925    int res;
02926    int len;
02927    char eid_str[20];
02928    len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
02929    /* Reserve enough space for encryption */
02930    if (ast_test_flag(trans, FLAG_ENCRYPT))
02931       len += 384;
02932    pack = ast_calloc(1, len);
02933    if (pack) {
02934       pack->h = (struct dundi_hdr *)(pack->data);
02935       if (cmdresp != DUNDI_COMMAND_ACK) {
02936          pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
02937          pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
02938          AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
02939       }
02940       pack->parent = trans;
02941       pack->h->strans = htons(trans->strans);
02942       pack->h->dtrans = htons(trans->dtrans);
02943       pack->h->iseqno = trans->iseqno;
02944       pack->h->oseqno = trans->oseqno;
02945       pack->h->cmdresp = cmdresp;
02946       pack->datalen = sizeof(struct dundi_hdr);
02947       if (ied) {
02948          memcpy(pack->h->ies, ied->buf, ied->pos);
02949          pack->datalen += ied->pos;
02950       } 
02951       if (final) {
02952          pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
02953          ast_set_flag(trans, FLAG_FINAL);
02954       }
02955       pack->h->cmdflags = flags;
02956       if (cmdresp != DUNDI_COMMAND_ACK) {
02957          trans->oseqno++;
02958          trans->oseqno = trans->oseqno % 256;
02959       }
02960       trans->aseqno = trans->iseqno;
02961       /* If we have their public key, encrypt */
02962       if (ast_test_flag(trans, FLAG_ENCRYPT)) {
02963          switch(cmdresp) {
02964          case DUNDI_COMMAND_REGREQ:
02965          case DUNDI_COMMAND_REGRESPONSE:
02966          case DUNDI_COMMAND_DPDISCOVER:
02967          case DUNDI_COMMAND_DPRESPONSE:
02968          case DUNDI_COMMAND_EIDQUERY:
02969          case DUNDI_COMMAND_EIDRESPONSE:
02970          case DUNDI_COMMAND_PRECACHERQ:
02971          case DUNDI_COMMAND_PRECACHERP:
02972             if (dundidebug)
02973                dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
02974             res = dundi_encrypt(trans, pack);
02975             break;
02976          default:
02977             res = 0;
02978          }
02979       } else 
02980          res = 0;
02981       if (!res) 
02982          res = dundi_xmit(pack);
02983       if (res)
02984          ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
02985             
02986       if (cmdresp == DUNDI_COMMAND_ACK)
02987          free(pack);
02988       return res;
02989    }
02990    return -1;
02991 }

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

Definition at line 2542 of file pbx_dundi.c.

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

02543 {
02544    char eid_str[20];
02545    if (argc != 3)
02546       return RESULT_SHOWUSAGE;
02547    AST_LIST_LOCK(&peers);
02548    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02549    AST_LIST_UNLOCK(&peers);
02550    ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
02551    return RESULT_SUCCESS;
02552 }

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

Definition at line 2576 of file pbx_dundi.c.

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

02577 {
02578 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
02579 #define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
02580    struct dundi_mapping *map;
02581    char fs[256];
02582    if (argc != 3)
02583       return RESULT_SHOWUSAGE;
02584    AST_LIST_LOCK(&peers);
02585    ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
02586    AST_LIST_TRAVERSE(&mappings, map, list) {
02587       ast_cli(fd, FORMAT, map->dcontext, map->weight, 
02588          ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 
02589          dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
02590    }
02591    AST_LIST_UNLOCK(&peers);
02592    return RESULT_SUCCESS;
02593 #undef FORMAT
02594 #undef FORMAT2
02595 }

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

Definition at line 2375 of file pbx_dundi.c.

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

02376 {
02377    struct dundi_peer *peer;
02378    struct permission *p;
02379    char *order;
02380    char eid_str[20];
02381    int x, cnt;
02382    
02383    if (argc != 4)
02384       return RESULT_SHOWUSAGE;
02385    AST_LIST_LOCK(&peers);
02386    AST_LIST_TRAVERSE(&peers, peer, list) {
02387       if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), argv[3]))
02388          break;
02389    }
02390    if (peer) {
02391       switch(peer->order) {
02392       case 0:
02393          order = "Primary";
02394          break;
02395       case 1:
02396          order = "Secondary";
02397          break;
02398       case 2:
02399          order = "Tertiary";
02400          break;
02401       case 3:
02402          order = "Quartiary";
02403          break;
02404       default:
02405          order = "Unknown";
02406       }
02407       ast_cli(fd, "Peer:    %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
02408       ast_cli(fd, "Model:   %s\n", model2str(peer->model));
02409       ast_cli(fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
02410       ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
02411       ast_cli(fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");
02412       ast_cli(fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
02413       ast_cli(fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
02414       if (!AST_LIST_EMPTY(&peer->include))
02415          ast_cli(fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
02416       AST_LIST_TRAVERSE(&peer->include, p, list)
02417          ast_cli(fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
02418       if (!AST_LIST_EMPTY(&peer->permit))
02419          ast_cli(fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
02420       AST_LIST_TRAVERSE(&peer->permit, p, list)
02421          ast_cli(fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
02422       cnt = 0;
02423       for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
02424          if (peer->lookups[x]) {
02425             if (!cnt)
02426                ast_cli(fd, "Last few query times:\n");
02427             ast_cli(fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
02428             cnt++;
02429          }
02430       }
02431       if (cnt)
02432          ast_cli(fd, "Average query time: %d ms\n", peer->avgms);
02433    } else
02434       ast_cli(fd, "No such peer '%s'\n", argv[3]);
02435    AST_LIST_UNLOCK(&peers);
02436    return RESULT_SUCCESS;
02437 }

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

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

02440 {
02441 #define FORMAT2 "%-20.20s %-15.15s     %-10.10s %-8.8s %-15.15s\n"
02442 #define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
02443    struct dundi_peer *peer;
02444    int registeredonly=0;
02445    char avgms[20];
02446    char eid_str[20];
02447    int online_peers = 0;
02448    int offline_peers = 0;
02449    int unmonitored_peers = 0;
02450    int total_peers = 0;
02451 
02452    if ((argc != 3) && (argc != 4) && (argc != 5))
02453       return RESULT_SHOWUSAGE;
02454    if ((argc == 4)) {
02455       if (!strcasecmp(argv[3], "registered")) {
02456          registeredonly = 1;
02457       } else
02458          return RESULT_SHOWUSAGE;
02459    }
02460    AST_LIST_LOCK(&peers);
02461    ast_cli(fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status");
02462    AST_LIST_TRAVERSE(&peers, peer, list) {
02463       char status[20];
02464       int print_line = -1;
02465       char srch[2000];
02466       total_peers++;
02467       if (registeredonly && !peer->addr.sin_addr.s_addr)
02468          continue;
02469       if (peer->maxms) {
02470          if (peer->lastms < 0) {
02471             strcpy(status, "UNREACHABLE");
02472             offline_peers++;
02473          }
02474          else if (peer->lastms > peer->maxms) {
02475             snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
02476             offline_peers++;
02477          }
02478          else if (peer->lastms) {
02479             snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
02480             online_peers++;
02481          }
02482          else {
02483             strcpy(status, "UNKNOWN");
02484             offline_peers++;
02485          }
02486       } else {
02487          strcpy(status, "Unmonitored");
02488          unmonitored_peers++;
02489       }
02490       if (peer->avgms) 
02491          snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
02492       else
02493          strcpy(avgms, "Unavail");
02494       snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02495                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02496                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02497 
02498                 if (argc == 5) {
02499                   if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) {
02500                         print_line = -1;
02501                    } else if (!strcasecmp(argv[3],"exclude") && !strstr(srch,argv[4])) {
02502                         print_line = 1;
02503                    } else if (!strcasecmp(argv[3],"begin") && !strncasecmp(srch,argv[4],strlen(argv[4]))) {
02504                         print_line = -1;
02505                    } else {
02506                         print_line = 0;
02507                   }
02508                 }
02509       
02510         if (print_line) {
02511          ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 
02512                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
02513                peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
02514       }
02515    }
02516    ast_cli(fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
02517    AST_LIST_UNLOCK(&peers);
02518    return RESULT_SUCCESS;
02519 #undef FORMAT
02520 #undef FORMAT2
02521 }

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

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

02598 {
02599 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
02600 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
02601    struct dundi_precache_queue *qe;
02602    int h,m,s;
02603    time_t now;
02604    
02605    if (argc != 3)
02606       return RESULT_SHOWUSAGE;
02607    time(&now);
02608    ast_cli(fd, FORMAT2, "Number", "Context", "Expiration");
02609    AST_LIST_LOCK(&pcq);
02610    AST_LIST_TRAVERSE(&pcq, qe, list) {
02611       s = qe->expiration - now;
02612       h = s / 3600;
02613       s = s % 3600;
02614       m = s / 60;
02615       s = s % 60;
02616       ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s);
02617    }
02618    AST_LIST_UNLOCK(&pcq);
02619    
02620    return RESULT_SUCCESS;
02621 #undef FORMAT
02622 #undef FORMAT2
02623 }

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

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

02555 {
02556 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
02557 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
02558    struct dundi_request *req;
02559    char eidstr[20];
02560    if (argc != 3)
02561       return RESULT_SHOWUSAGE;
02562    AST_LIST_LOCK(&peers);
02563    ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
02564    AST_LIST_TRAVERSE(&requests, req, list) {
02565       ast_cli(fd, FORMAT, req->number, req->dcontext,
02566          dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
02567    }
02568    AST_LIST_UNLOCK(&peers);
02569    return RESULT_SUCCESS;
02570 #undef FORMAT
02571 #undef FORMAT2
02572 }

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

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

02524 {
02525 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
02526 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
02527    struct dundi_transaction *trans;
02528    if (argc != 3)
02529       return RESULT_SHOWUSAGE;
02530    AST_LIST_LOCK(&peers);
02531    ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
02532    AST_LIST_TRAVERSE(&alltrans, trans, all) {
02533       ast_cli(fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 
02534          ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
02535    }
02536    AST_LIST_UNLOCK(&peers);
02537    return RESULT_SUCCESS;
02538 #undef FORMAT
02539 #undef FORMAT2
02540 }

static int dundi_xmit ( struct dundi_packet pack  )  [static]

Definition at line 2787 of file pbx_dundi.c.

References ast_inet_ntoa(), ast_log(), dundi_showframe(), dundidebug, LOG_WARNING, and netsocket.

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

02788 {
02789    int res;
02790    if (dundidebug)
02791       dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
02792    res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
02793    if (res < 0) {
02794       ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 
02795          ast_inet_ntoa(pack->parent->addr.sin_addr),
02796          ntohs(pack->parent->addr.sin_port), strerror(errno));
02797    }
02798    if (res > 0)
02799       res = 0;
02800    return res;
02801 }

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

Definition at line 3739 of file pbx_dundi.c.

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

03740 {
03741    char *context;
03742    char *opts;
03743    int results;
03744    int x;
03745    int bypass = 0;
03746    struct ast_module_user *u;
03747    struct dundi_result dr[MAX_RESULTS];
03748 
03749    buf[0] = '\0';
03750 
03751    if (ast_strlen_zero(num)) {
03752       ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
03753       return -1;
03754    }
03755 
03756    u = ast_module_user_add(chan);
03757 
03758    context = strchr(num, '|');
03759    if (context) {
03760       *context++ = '\0';
03761       opts = strchr(context, '|');
03762       if (opts) {
03763          *opts++ = '\0';
03764          if (strchr(opts, 'b'))
03765             bypass = 1;
03766       }
03767    }
03768 
03769    if (ast_strlen_zero(context))
03770       context = "e164";
03771    
03772    results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
03773    if (results > 0) {
03774       sort_results(dr, results);
03775       for (x = 0; x < results; x++) {
03776          if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
03777             snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
03778             break;
03779          }
03780       }
03781    }
03782 
03783    ast_module_user_remove(u);
03784 
03785    return 0;
03786 }

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

Definition at line 1318 of file pbx_dundi.c.

References aes_encrypt().

Referenced by dundi_encrypt().

01319 {
01320    unsigned char curblock[16];
01321    int x;
01322    memcpy(curblock, iv, sizeof(curblock));
01323    while(len > 0) {
01324       for (x=0;x<16;x++)
01325          curblock[x] ^= src[x];
01326       aes_encrypt(curblock, dst, ecx);
01327       memcpy(curblock, dst, sizeof(curblock)); 
01328       dst += 16;
01329       src += 16;
01330       len -= 16;
01331    }
01332    return 0;
01333 }

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

Definition at line 478 of file pbx_dundi.c.

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

00479 {
00480    struct dundi_peer *cur = NULL;
00481 
00482    if (!eid)
00483       eid = &empty_eid;
00484    
00485    AST_LIST_TRAVERSE(&peers, cur, list) {
00486       if (!dundi_eid_cmp(&cur->eid,eid))
00487          break;
00488    }
00489 
00490    return cur;
00491 }

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

Definition at line 326 of file pbx_dundi.c.

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

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

static int get_trans_id ( void   )  [static]

Definition at line 443 of file pbx_dundi.c.

References AST_LIST_TRAVERSE, ast_random(), and t.

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1496 of file pbx_dundi.c.

References dundi_peer::addr, dundi_transaction::addr, ast_clear_flag_nonstd, ast_db_put(), ast_inet_ntoa(), ast_log(), ast_sched_add(), ast_sched_del(), ast_set_flag_nonstd, ast_strlen_zero(), ast_test_flag, ast_test_flag_nonstd, ast_verbose(), cache_save(), cache_save_hint(), dundi_hdr::cmdresp, default_expiration, do_register_expire(), dundi_answer_entity(), dundi_answer_query(), dundi_cache_time, DUNDI_CAUSE_GENERAL, DUNDI_CAUSE_NOAUTH, DUNDI_COMMAND_CANCEL, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, dundi_eid_to_str(), dundi_eid_to_str_short(), DUNDI_HINT_DONT_ASK, DUNDI_HINT_TTL_EXPIRED, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), dundi_ie_append_short(), DUNDI_IE_CAUSE, DUNDI_IE_EXPIRATION, DUNDI_MODEL_INBOUND, dundi_parse_ies(), dundi_prop_precache(), dundi_send(), dundi_peer::eid, find_peer(), FLAG_ENCRYPT, dundi_transaction::flags, has_permission(), dundi_hdr::ies, ies, inaddrcmp(), LOG_DEBUG, LOG_NOTICE, LOG_WARNING, option_verbose, dundi_hdr::oseqno, qualify_peer(), tech2str(), dundi_transaction::them_eid, dundi_transaction::us_eid, and VERBOSE_PREFIX_3.

Referenced by handle_frame().

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

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

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

01924 {
01925    struct dundi_transaction *trans;
01926    trans = find_transaction(h, sin);
01927    if (!trans) {
01928       dundi_reject(h, sin);
01929       return 0;
01930    }
01931    /* Got a transaction, see where this header fits in */
01932    if (h->oseqno == trans->iseqno) {
01933       /* Just what we were looking for...  Anything but ack increments iseqno */
01934       if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
01935          /* If final, we're done */
01936          destroy_trans(trans, 0);
01937          return 0;
01938       }
01939       if (h->cmdresp != DUNDI_COMMAND_ACK) {
01940          trans->oiseqno = trans->iseqno;
01941          trans->iseqno++;
01942          handle_command_response(trans, h, datalen, 0);
01943       }
01944       if (trans->aseqno != trans->iseqno) {
01945          dundi_ack(trans, h->cmdresp & 0x80);
01946          trans->aseqno = trans->iseqno;
01947       }
01948       /* Delete any saved last transmissions */
01949       destroy_packets(&trans->lasttrans);
01950       if (h->cmdresp & 0x80) {
01951          /* Final -- destroy now */
01952          destroy_trans(trans, 0);
01953       }
01954    } else if (h->oseqno == trans->oiseqno) {
01955       /* Last incoming sequence number -- send ACK without processing */
01956       dundi_ack(trans, 0);
01957    } else {
01958       /* Out of window -- simply drop */
01959       ast_log(LOG_DEBUG, "Dropping packet out of window!\n");
01960    }
01961    return 0;
01962 }

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

Definition at line 282 of file pbx_dundi.c.

References AST_LIST_TRAVERSE.

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

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

static int load_module ( void   )  [static]

Definition at line 4502 of file pbx_dundi.c.

References ast_cli_register_multiple(), ast_custom_function_register(), ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_switch(), ast_verbose(), cli_dundi, dundi_debug_output(), dundi_error_output(), dundi_function, DUNDI_PORT, dundi_set_error(), dundi_set_output(), dundi_switch, io, io_context_create(), LOG_ERROR, netsocket, option_verbose, sched_context_create(), set_config(), start_network_thread(), tos, and VERBOSE_PREFIX_2.

04503 {
04504    int res = 0;
04505    struct sockaddr_in sin;
04506 
04507    if(set_config("dundi.conf",&sin))
04508       return AST_MODULE_LOAD_DECLINE;
04509 
04510    dundi_set_output(dundi_debug_output);
04511    dundi_set_error(dundi_error_output);
04512    
04513    sin.sin_family = AF_INET;
04514    sin.sin_port = ntohs(DUNDI_PORT);
04515    sin.sin_addr.s_addr = INADDR_ANY;
04516 
04517    /* Make a UDP socket */
04518    io = io_context_create();
04519    sched = sched_context_create();
04520    
04521    if (!io || !sched) {
04522       ast_log(LOG_ERROR, "Out of memory\n");
04523       return -1;
04524    }
04525 
04526    netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
04527    
04528    if (netsocket < 0) {
04529       ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
04530       return -1;
04531    }
04532    if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
04533       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));
04534       return -1;
04535    }
04536 
04537    if (option_verbose > 1)
04538       ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
04539 
04540    if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
04541       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
04542    
04543    res = start_network_thread();
04544    if (res) {
04545       ast_log(LOG_ERROR, "Unable to start network thread\n");
04546       close(netsocket);
04547       return -1;
04548    }
04549 
04550    if (option_verbose > 1)
04551       ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
04552 
04553    ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04554    if (ast_register_switch(&dundi_switch))
04555       ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
04556    ast_custom_function_register(&dundi_function); 
04557    
04558    return res;
04559 }

static void load_password ( void   )  [static]

Definition at line 2020 of file pbx_dundi.c.

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

Referenced by set_config().

02021 {
02022    char *current=NULL;
02023    char *last=NULL;
02024    char tmp[256];
02025    time_t expired;
02026    
02027    ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
02028    if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
02029       ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
02030       current = strchr(tmp, ';');
02031       if (!current)
02032          current = tmp;
02033       else {
02034          *current = '\0';
02035          current++;
02036       };
02037       if ((time(NULL) - expired) < 0) {
02038          if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
02039             expired = time(NULL) + DUNDI_SECRET_TIME;
02040       } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
02041          last = current;
02042          current = NULL;
02043       } else {
02044          last = NULL;
02045          current = NULL;
02046       }
02047    }
02048    if (current) {
02049       /* Current key is still valid, just setup rotatation properly */
02050       ast_copy_string(cursecret, current, sizeof(cursecret));
02051       rotatetime = expired;
02052    } else {
02053       /* Current key is out of date, rotate or eliminate all together */
02054       build_secret(cursecret, sizeof(cursecret));
02055       save_secret(cursecret, last);
02056    }
02057 }

static void mark_mappings ( void   )  [static]

Definition at line 3815 of file pbx_dundi.c.

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

Referenced by set_config().

03816 {
03817    struct dundi_mapping *map;
03818    
03819    AST_LIST_LOCK(&peers);
03820    AST_LIST_TRAVERSE(&mappings, map, list) {
03821       map->dead = 1;
03822    }
03823    AST_LIST_UNLOCK(&peers);
03824 }

static void mark_peers ( void   )  [static]

Definition at line 3805 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by set_config().

03806 {
03807    struct dundi_peer *peer;
03808    AST_LIST_LOCK(&peers);
03809    AST_LIST_TRAVERSE(&peers, peer, list) {
03810       peer->dead = 1;
03811    }
03812    AST_LIST_UNLOCK(&peers);
03813 }

static char* model2str ( int  model  )  [static]

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

02216 {
02217    switch(model) {
02218    case DUNDI_MODEL_INBOUND:
02219       return "Inbound";
02220    case DUNDI_MODEL_OUTBOUND:
02221       return "Outbound";
02222    case DUNDI_MODEL_SYMMETRIC:
02223       return "Symmetric";
02224    default:
02225       return "Unknown";
02226    }
02227 }

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

Definition at line 2076 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(), dundi_shutdown, io, netsocket, netthreadid, peers, and socket_read().

02077 {
02078    /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
02079       from the network, and queue them for delivery to the channels */
02080    int res;
02081    /* Establish I/O callback for socket read */
02082    ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
02083    
02084    while (!dundi_shutdown) {
02085       res = ast_sched_wait(sched);
02086       if ((res > 1000) || (res < 0))
02087          res = 1000;
02088       res = ast_io_wait(io, res);
02089       if (res >= 0) {
02090          AST_LIST_LOCK(&peers);
02091          ast_sched_runq(sched);
02092          AST_LIST_UNLOCK(&peers);
02093       }
02094       check_password();
02095    }
02096 
02097    netthreadid = AST_PTHREADT_NULL;
02098    
02099    return NULL;
02100 }

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

Definition at line 3197 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, dr, dundi_eid_cmp(), DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), peers, dundi_transaction::them_eid, and dundi_transaction::us_eid.

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

03198 {
03199    /* Minimize the message propagation through DUNDi by
03200       alerting the network to hops which should be not be considered */
03201    struct dundi_transaction *trans;
03202    struct dundi_peer *peer;
03203    dundi_eid tmp;
03204    int x;
03205    int needpush;
03206 
03207    AST_LIST_LOCK(&peers);
03208    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03209       /* Pop off the true root */
03210       if (trans->eidcount) {
03211          tmp = trans->eids[--trans->eidcount];
03212          needpush = 1;
03213       } else {
03214          tmp = trans->us_eid;
03215          needpush = 0;
03216       }
03217 
03218       AST_LIST_TRAVERSE(&peers, peer, list) {
03219          if (has_permission(&peer->include, dr->dcontext) && 
03220              dundi_eid_cmp(&peer->eid, &trans->them_eid) &&
03221             (peer->order <= order)) {
03222             /* For each other transaction, make sure we don't
03223                ask this EID about the others if they're not
03224                already in the list */
03225             if (!dundi_eid_cmp(&tmp, &peer->eid)) 
03226                x = -1;
03227             else {
03228                for (x=0;x<trans->eidcount;x++) {
03229                   if (!dundi_eid_cmp(&trans->eids[x], &peer->eid))
03230                      break;
03231                }
03232             }
03233             if (x == trans->eidcount) {
03234                /* Nope not in the list, if needed, add us at the end since we're the source */
03235                if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
03236                   trans->eids[trans->eidcount++] = peer->eid;
03237                   /* Need to insert the real root (or us) at the bottom now as
03238                      a requirement now.  */
03239                   needpush = 1;
03240                }
03241             }
03242          }
03243       }
03244       /* If necessary, push the true root back on the end */
03245       if (needpush)
03246          trans->eids[trans->eidcount++] = tmp;
03247    }
03248    AST_LIST_UNLOCK(&peers);
03249 
03250    return 0;
03251 }

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

Definition at line 4027 of file pbx_dundi.c.

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

Referenced by build_peer().

04028 {
04029    char data[256];
04030    char *c;
04031    int port, expire;
04032    char eid_str[20];
04033    dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
04034    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04035       c = strchr(data, ':');
04036       if (c) {
04037          *c = '\0';
04038          c++;
04039          if (sscanf(c, "%d:%d", &port, &expire) == 2) {
04040             /* Got it! */
04041             inet_aton(data, &peer->addr.sin_addr);
04042             peer->addr.sin_family = AF_INET;
04043             peer->addr.sin_port = htons(port);
04044             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04045          }
04046       }
04047    }
04048 }

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

Definition at line 3050 of file pbx_dundi.c.

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

Referenced by precache_transactions().

03051 {
03052    struct dundi_ie_data ied;
03053    int x, res;
03054    int max = 999999;
03055    int expiration = dundi_cache_time;
03056    int ouranswers=0;
03057    dundi_eid *avoid[1] = { NULL, };
03058    int direct[1] = { 0, };
03059    struct dundi_result dr[MAX_RESULTS];
03060    struct dundi_hint_metadata hmd;
03061    if (!trans->parent) {
03062       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03063       return -1;
03064    }
03065    memset(&hmd, 0, sizeof(hmd));
03066    memset(&dr, 0, sizeof(dr));
03067    /* Look up the answers we're going to include */
03068    for (x=0;x<mapcount;x++)
03069       ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
03070    if (ouranswers < 0)
03071       ouranswers = 0;
03072    for (x=0;x<ouranswers;x++) {
03073       if (dr[x].weight < max)
03074          max = dr[x].weight;
03075    }
03076    if (max) {
03077       /* If we do not have a canonical result, keep looking */
03078       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);
03079       if (res > 0) {
03080          /* Append answer in result */
03081          ouranswers += res;
03082       }
03083    }
03084    
03085    if (ouranswers > 0) {
03086       *foundanswers += ouranswers;
03087       memset(&ied, 0, sizeof(ied));
03088       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03089       if (!dundi_eid_zero(&trans->us_eid))
03090          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03091       for (x=0;x<trans->eidcount;x++)
03092          dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03093       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03094       dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03095       dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03096       for (x=0;x<ouranswers;x++) {
03097          /* Add answers */
03098          if (dr[x].expiration && (expiration > dr[x].expiration))
03099             expiration = dr[x].expiration;
03100          dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
03101       }
03102       dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
03103       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
03104       if (trans->autokilltimeout)
03105          trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03106       if (expiration < *minexp)
03107          *minexp = expiration;
03108       return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
03109    } else {
03110       /* Oops, nothing to send... */
03111       destroy_trans(trans, 0);
03112       return 0;
03113    }
03114 }

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

Definition at line 3149 of file pbx_dundi.c.

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

Referenced by dundi_precache_internal().

03150 {
03151    struct dundi_transaction *trans;
03152 
03153    /* Mark all as "in thread" so they don't disappear */
03154    AST_LIST_LOCK(&peers);
03155    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03156       if (trans->thread)
03157          ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
03158       trans->thread = 1;
03159    }
03160    AST_LIST_UNLOCK(&peers);
03161 
03162    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03163       if (!ast_test_flag(trans, FLAG_DEAD))
03164          precache_trans(trans, maps, mapcount, expiration, foundanswers);
03165    }
03166 
03167    /* Cleanup any that got destroyed in the mean time */
03168    AST_LIST_LOCK(&peers);
03169    AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
03170       trans->thread = 0;
03171       if (ast_test_flag(trans, FLAG_DEAD)) {
03172          ast_log(LOG_DEBUG, "Our transaction went away!\n");
03173          /* This is going to remove the transaction from the dundi_request's list, as well
03174           * as the global transactions list */
03175          destroy_trans(trans, 0);
03176       }
03177    }
03178    AST_LIST_TRAVERSE_SAFE_END
03179    AST_LIST_UNLOCK(&peers);
03180 
03181    return 0;
03182 }

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

Definition at line 2102 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(), dundi_shutdown, free, and precachethreadid.

Referenced by start_network_thread().

02103 {
02104    struct dundi_precache_queue *qe;
02105    time_t now;
02106    char context[256];
02107    char number[256];
02108    int run;
02109 
02110    while (!dundi_shutdown) {
02111       time(&now);
02112       run = 0;
02113       AST_LIST_LOCK(&pcq);
02114       if ((qe = AST_LIST_FIRST(&pcq))) {
02115          if (!qe->expiration) {
02116             /* Gone...  Remove... */
02117             AST_LIST_REMOVE_HEAD(&pcq, list);
02118             free(qe);
02119          } else if (qe->expiration < now) {
02120             /* Process this entry */
02121             qe->expiration = 0;
02122             ast_copy_string(context, qe->context, sizeof(context));
02123             ast_copy_string(number, qe->number, sizeof(number));
02124             run = 1;
02125          }
02126       }
02127       AST_LIST_UNLOCK(&pcq);
02128       if (run) {
02129          dundi_precache(context, number);
02130       } else
02131          sleep(1);
02132    }
02133 
02134    precachethreadid = AST_PTHREADT_NULL;
02135 
02136    return NULL;
02137 }

static void prune_mappings ( void   )  [static]

Definition at line 3867 of file pbx_dundi.c.

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

Referenced by set_config().

03868 {
03869    struct dundi_mapping *map;
03870 
03871    AST_LIST_LOCK(&peers);
03872    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
03873       if (map->dead) {
03874          AST_LIST_REMOVE_CURRENT(&mappings, list);
03875          destroy_map(map);
03876       }
03877    }
03878    AST_LIST_TRAVERSE_SAFE_END
03879    AST_LIST_UNLOCK(&peers);
03880 }

static void prune_peers ( void   )  [static]

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

03853 {
03854    struct dundi_peer *peer;
03855 
03856    AST_LIST_LOCK(&peers);
03857    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
03858       if (peer->dead) {
03859          AST_LIST_REMOVE_CURRENT(&peers, list);
03860          destroy_peer(peer);
03861       }
03862    }
03863    AST_LIST_TRAVERSE_SAFE_END
03864    AST_LIST_UNLOCK(&peers);
03865 }

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

Definition at line 4002 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 do_qualify(), and handle_command_response().

04003 {
04004    int when;
04005    if (peer->qualifyid > -1)
04006       ast_sched_del(sched, peer->qualifyid);
04007    peer->qualifyid = -1;
04008    if (peer->qualtrans)
04009       destroy_trans(peer->qualtrans, 0);
04010    peer->qualtrans = NULL;
04011    if (peer->maxms > 0) {
04012       when = 60000;
04013       if (peer->lastms < 0)
04014          when = 10000;
04015       if (schedonly)
04016          when = 5000;
04017       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04018       if (!schedonly)
04019          peer->qualtrans = create_transaction(peer);
04020       if (peer->qualtrans) {
04021          peer->qualtx = ast_tvnow();
04022          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04023          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04024       }
04025    }
04026 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3184 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

03185 {
03186    struct dundi_transaction *trans;
03187 
03188    AST_LIST_LOCK(&peers);
03189    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03190       dundi_query(trans);
03191    }
03192    AST_LIST_UNLOCK(&peers);
03193 
03194    return 0;
03195 }

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

Definition at line 3365 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03366 {
03367    struct dundi_request *cur;
03368    int res=0;
03369    char eid_str[20];
03370    AST_LIST_LOCK(&peers);
03371    AST_LIST_TRAVERSE(&requests, cur, list) {
03372       if (option_debug)
03373          ast_log(LOG_DEBUG, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
03374             dr->dcontext, dr->number);
03375       if (!strcasecmp(cur->dcontext, dr->dcontext) &&
03376           !strcasecmp(cur->number, dr->number) &&
03377           (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
03378          ast_log(LOG_DEBUG, "Found existing query for '%s@%s' for '%s' crc '%08lx'\n", 
03379             cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
03380          *pending = cur;
03381          res = 1;
03382          break;
03383       }
03384    }
03385    if (!res) {
03386       ast_log(LOG_DEBUG, "Registering request for '%s@%s' on behalf of '%s' crc '%08lx'\n", 
03387             dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
03388       /* Go ahead and link us in since nobody else is searching for this */
03389       AST_LIST_INSERT_HEAD(&requests, dr, list);
03390       *pending = NULL;
03391    }
03392    AST_LIST_UNLOCK(&peers);
03393    return res;
03394 }

static int reload ( void   )  [static]

Definition at line 4495 of file pbx_dundi.c.

References set_config().

04496 {
04497    struct sockaddr_in sin;
04498    set_config("dundi.conf",&sin);
04499    return 0;
04500 }

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

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

03546 {
03547    int len;
03548    struct dundi_precache_queue *qe, *prev;
03549 
03550    AST_LIST_LOCK(&pcq);
03551    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03552       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03553          AST_LIST_REMOVE_CURRENT(&pcq, list);
03554          break;
03555       }
03556    }
03557    AST_LIST_TRAVERSE_SAFE_END
03558    if (!qe) {
03559       len = sizeof(*qe);
03560       len += strlen(number) + 1;
03561       len += strlen(context) + 1;
03562       if (!(qe = ast_calloc(1, len))) {
03563          AST_LIST_UNLOCK(&pcq);
03564          return;
03565       }
03566       strcpy(qe->number, number);
03567       qe->context = qe->number + strlen(number) + 1;
03568       strcpy(qe->context, context);
03569    }
03570    time(&qe->expiration);
03571    qe->expiration += expiration;
03572    if ((prev = AST_LIST_FIRST(&pcq))) {
03573       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03574          prev = AST_LIST_NEXT(prev, list);
03575       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03576    } else
03577       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03578    AST_LIST_UNLOCK(&pcq);
03579 }

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

Definition at line 2254 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02255 {
02256    const struct dundi_result *resa, *resb;
02257    resa = a;
02258    resb = b;
02259    if (resa->weight < resb->weight)
02260       return -1;
02261    if (resa->weight > resb->weight)
02262       return 1;
02263    return 0;
02264 }

static void reset_global_eid ( void   )  [static]

Definition at line 396 of file pbx_dundi.c.

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

Referenced by set_config().

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

static int reset_transaction ( struct dundi_transaction trans  )  [static]

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

00463 {
00464    int tid;
00465    tid = get_trans_id();
00466    if (tid < 1)
00467       return -1;
00468    trans->strans = tid;
00469    trans->dtrans = 0;
00470    trans->iseqno = 0;
00471    trans->oiseqno = 0;
00472    trans->oseqno = 0;
00473    trans->aseqno = 0;
00474    ast_clear_flag(trans, FLAG_FINAL);  
00475    return 0;
00476 }

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

Definition at line 2007 of file pbx_dundi.c.

References ast_db_put(), DUNDI_SECRET_TIME, rotatetime, and secretpath.

Referenced by check_password(), and load_password().

02008 {
02009    char tmp[256];
02010    if (oldkey)
02011       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02012    else
02013       snprintf(tmp, sizeof(tmp), "%s", newkey);
02014    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02015    ast_db_put(secretpath, "secret", tmp);
02016    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02017    ast_db_put(secretpath, "secretexpiry", tmp);
02018 }

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

Definition at line 4315 of file pbx_dundi.c.

References 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(), authdebug, build_mapping(), build_peer(), country, DEFAULT_MAXMS, dept, dundi_cache_time, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), dundi_str_to_eid(), dundi_ttl, email, format, global_autokilltimeout, global_eid, global_storehistory, hp, ipaddr, IPTOS_MINCOST, ast_variable::lineno, load_password(), locality, LOG_ERROR, LOG_NOTICE, mark_mappings(), mark_peers(), ast_variable::name, ast_variable::next, org, peers, phone, prune_mappings(), prune_peers(), reset_global_eid(), secretpath, stateprov, tos, and ast_variable::value.

04316 {
04317    struct ast_config *cfg;
04318    struct ast_variable *v;
04319    char *cat;
04320    int format;
04321    int x;
04322    char hn[MAXHOSTNAMELEN] = "";
04323    struct ast_hostent he;
04324    struct hostent *hp;
04325    struct sockaddr_in sin2;
04326    static int last_port = 0;
04327    int globalpcmodel = 0;
04328    dundi_eid testeid;
04329 
04330    dundi_ttl = DUNDI_DEFAULT_TTL;
04331    dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
04332    cfg = ast_config_load(config_file);
04333    
04334    
04335    if (!cfg) {
04336       ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
04337       return -1;
04338    }
04339    ipaddr[0] = '\0';
04340    if (!gethostname(hn, sizeof(hn)-1)) {
04341       hp = ast_gethostbyname(hn, &he);
04342       if (hp) {
04343          memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
04344          ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
04345       } else
04346          ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
04347    } else
04348       ast_log(LOG_WARNING, "Unable to get host name!\n");
04349    AST_LIST_LOCK(&peers);
04350    reset_global_eid();
04351    global_storehistory = 0;
04352    ast_copy_string(secretpath, "dundi", sizeof(secretpath));
04353    v = ast_variable_browse(cfg, "general");
04354    while(v) {
04355       if (!strcasecmp(v->name, "port")){ 
04356          sin->sin_port = ntohs(atoi(v->value));
04357          if(last_port==0){
04358             last_port=sin->sin_port;
04359          } else if(sin->sin_port != last_port)
04360             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
04361       } else if (!strcasecmp(v->name, "bindaddr")) {
04362          struct hostent *hp;
04363          struct ast_hostent he;
04364          hp = ast_gethostbyname(v->value, &he);
04365          if (hp) {
04366             memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
04367          } else
04368             ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
04369       } else if (!strcasecmp(v->name, "authdebug")) {
04370          authdebug = ast_true(v->value);
04371       } else if (!strcasecmp(v->name, "ttl")) {
04372          if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
04373             dundi_ttl = x;
04374          } else {
04375             ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
04376                v->value, v->lineno, DUNDI_DEFAULT_TTL);
04377          }
04378       } else if (!strcasecmp(v->name, "autokill")) {
04379          if (sscanf(v->value, "%d", &x) == 1) {
04380             if (x >= 0)
04381                global_autokilltimeout = x;
04382             else
04383                ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
04384          } else if (ast_true(v->value)) {
04385             global_autokilltimeout = DEFAULT_MAXMS;
04386          } else {
04387             global_autokilltimeout = 0;
04388          }
04389       } else if (!strcasecmp(v->name, "entityid")) {
04390          if (!dundi_str_to_eid(&testeid, v->value))
04391             global_eid = testeid;
04392          else
04393             ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
04394       } else if (!strcasecmp(v->name, "tos")) {
04395          if (sscanf(v->value, "%d", &format) == 1)
04396             tos = format & 0xff;
04397          else if (!strcasecmp(v->value, "lowdelay"))
04398             tos = IPTOS_LOWDELAY;
04399          else if (!strcasecmp(v->value, "throughput"))
04400             tos = IPTOS_THROUGHPUT;
04401          else if (!strcasecmp(v->value, "reliability"))
04402             tos = IPTOS_RELIABILITY;
04403 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04404          else if (!strcasecmp(v->value, "mincost"))
04405             tos = IPTOS_MINCOST;
04406 #endif
04407          else if (!strcasecmp(v->value, "none"))
04408             tos = 0;
04409          else
04410 #if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS)
04411             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
04412 #else
04413             ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', or 'none'\n", v->lineno);
04414 #endif
04415       } else if (!strcasecmp(v->name, "department")) {
04416          ast_copy_string(dept, v->value, sizeof(dept));
04417       } else if (!strcasecmp(v->name, "organization")) {
04418          ast_copy_string(org, v->value, sizeof(org));
04419       } else if (!strcasecmp(v->name, "locality")) {
04420          ast_copy_string(locality, v->value, sizeof(locality));
04421       } else if (!strcasecmp(v->name, "stateprov")) {
04422          ast_copy_string(stateprov, v->value, sizeof(stateprov));
04423       } else if (!strcasecmp(v->name, "country")) {
04424          ast_copy_string(country, v->value, sizeof(country));
04425       } else if (!strcasecmp(v->name, "email")) {
04426          ast_copy_string(email, v->value, sizeof(email));
04427       } else if (!strcasecmp(v->name, "phone")) {
04428          ast_copy_string(phone, v->value, sizeof(phone));
04429       } else if (!strcasecmp(v->name, "storehistory")) {
04430          global_storehistory = ast_true(v->value);
04431       } else if (!strcasecmp(v->name, "cachetime")) {
04432          if ((sscanf(v->value, "%d", &x) == 1)) {
04433             dundi_cache_time = x;
04434          } else {
04435             ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
04436                v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
04437          }
04438       }
04439       v = v->next;
04440    }
04441    AST_LIST_UNLOCK(&peers);
04442    mark_mappings();
04443    v = ast_variable_browse(cfg, "mappings");
04444    while(v) {
04445       build_mapping(v->name, v->value);
04446       v = v->next;
04447    }
04448    prune_mappings();
04449    mark_peers();
04450    cat = ast_category_browse(cfg, NULL);
04451    while(cat) {
04452       if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
04453          /* Entries */
04454          if (!dundi_str_to_eid(&testeid, cat))
04455             build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
04456          else
04457             ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
04458       }
04459       cat = ast_category_browse(cfg, cat);
04460    }
04461    prune_peers();
04462    ast_config_destroy(cfg);
04463    load_password();
04464    if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
04465       dundi_precache_full();
04466    return 0;
04467 }

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

Definition at line 1964 of file pbx_dundi.c.

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

01965 {
01966    struct sockaddr_in sin;
01967    int res;
01968    struct dundi_hdr *h;
01969    char buf[MAX_PACKET_SIZE];
01970    socklen_t len;
01971    len = sizeof(sin);
01972    res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
01973    if (res < 0) {
01974       if (errno != ECONNREFUSED)
01975          ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
01976       return 1;
01977    }
01978    if (res < sizeof(struct dundi_hdr)) {
01979       ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
01980       return 1;
01981    }
01982    buf[res] = '\0';
01983    h = (struct dundi_hdr *)buf;
01984    if (dundidebug)
01985       dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
01986    AST_LIST_LOCK(&peers);
01987    handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
01988    AST_LIST_UNLOCK(&peers);
01989    return 1;
01990 }

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

Definition at line 2266 of file pbx_dundi.c.

References rescomp().

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

02267 {
02268    qsort(results, count, sizeof(results[0]), rescomp);
02269 }

static int start_network_thread ( void   )  [static]

Definition at line 2139 of file pbx_dundi.c.

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

02140 {
02141    ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
02142    ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
02143    return 0;
02144 }

static int str2tech ( char *  str  )  [static]

Definition at line 311 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

Definition at line 295 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, DUNDI_PROTO_NONE, and DUNDI_PROTO_SIP.

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

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

static int unload_module ( void   )  [static]

Definition at line 4469 of file pbx_dundi.c.

References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_module_user_hangup_all, AST_PTHREADT_NULL, ast_unregister_switch(), cli_dundi, dundi_function, dundi_shutdown, dundi_switch, io, io_context_destroy(), netsocket, netthreadid, precachethreadid, and sched_context_destroy().

04470 {
04471    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid;
04472    ast_module_user_hangup_all();
04473 
04474    /* Stop all currently running threads */
04475    dundi_shutdown = 1;
04476    if (previous_netthreadid != AST_PTHREADT_NULL) {
04477       pthread_kill(previous_netthreadid, SIGURG);
04478       pthread_join(previous_netthreadid, NULL);
04479    }
04480    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04481       pthread_kill(previous_precachethreadid, SIGURG);
04482       pthread_join(previous_precachethreadid, NULL);
04483    }
04484 
04485    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04486    ast_unregister_switch(&dundi_switch);
04487    ast_custom_function_unregister(&dundi_function);
04488    close(netsocket);
04489    io_context_destroy(io);
04490    sched_context_destroy(sched);
04491 
04492    return 0;
04493 }

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3396 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03397 {
03398    AST_LIST_LOCK(&peers);
03399    AST_LIST_REMOVE(&requests, dr, list);
03400    AST_LIST_UNLOCK(&peers);
03401 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1279 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_key_ttl, dundi_peer::eid, key(), and LOG_NOTICE.

Referenced by dundi_encrypt().

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


Variable Documentation

int authdebug = 0 [static]

Definition at line 117 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2695 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

char country[80] [static]

Definition at line 129 of file pbx_dundi.c.

Referenced by ind_load_module(), and set_config().

char cursecret[80] [static]

Definition at line 133 of file pbx_dundi.c.

Referenced by check_password(), and load_password().

char debug_usage[] [static]

Initial value:

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

Definition at line 2625 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 123 of file pbx_dundi.c.

Referenced by do_register(), and handle_command_response().

char dept[80] [static]

Definition at line 125 of file pbx_dundi.c.

Referenced by set_config().

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 120 of file pbx_dundi.c.

Referenced by dundi_lookup(), dundi_precache_internal(), handle_command_response(), precache_trans(), and set_config().

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 119 of file pbx_dundi.c.

Referenced by update_key().

int dundi_shutdown = 0 [static]

Definition at line 137 of file pbx_dundi.c.

Referenced by network_thread(), process_precache(), and unload_module().

struct ast_switch dundi_switch [static]

Definition at line 4305 of file pbx_dundi.c.

Referenced by load_module(), and unload_module().

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 118 of file pbx_dundi.c.

Referenced by dundi_lookup(), dundi_precache(), dundi_query_eid(), and set_config().

int dundidebug = 0 [static]

Definition at line 116 of file pbx_dundi.c.

Referenced by dundi_do_debug(), dundi_no_debug(), dundi_send(), dundi_xmit(), and socket_read().

char email[80] [static]

Definition at line 130 of file pbx_dundi.c.

Referenced by set_config().

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

Definition at line 136 of file pbx_dundi.c.

Referenced by find_peer().

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

int global_autokilltimeout = 0 [static]

Definition at line 121 of file pbx_dundi.c.

Referenced by apply_peer(), and set_config().

dundi_eid global_eid [static]

Definition at line 122 of file pbx_dundi.c.

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

int global_storehistory = 0 [static]

Definition at line 124 of file pbx_dundi.c.

Referenced by create_transaction(), dundi_do_store_history(), dundi_no_store_history(), and set_config().

struct io_context* io [static]

Definition at line 110 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 134 of file pbx_dundi.c.

Referenced by realtime_update_peer(), and set_config().

char locality[80] [static]

Definition at line 127 of file pbx_dundi.c.

Referenced by set_config().

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

int netsocket = -1 [static]

Definition at line 112 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), dundi_xmit(), handle_error(), load_module(), network_thread(), socket_read(), and unload_module().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 113 of file pbx_dundi.c.

char no_debug_usage[] [static]

Initial value:

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

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

char org[80] [static]

Definition at line 126 of file pbx_dundi.c.

Referenced by calc_crc(), and set_config().

char phone[80] [static]

Definition at line 131 of file pbx_dundi.c.

Referenced by privacy_exec(), and set_config().

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

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 114 of file pbx_dundi.c.

Referenced by process_precache(), start_network_thread(), and unload_module().

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

time_t rotatetime [static]

Definition at line 135 of file pbx_dundi.c.

Referenced by check_password(), load_password(), and save_secret().

struct sched_context* sched [static]

Definition at line 111 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 132 of file pbx_dundi.c.

Referenced by load_password(), save_secret(), and set_config().

char show_entityid_usage[] [static]

Initial value:

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

Definition at line 2659 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 2651 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 2663 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 2643 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 2655 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 2667 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 2647 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 128 of file pbx_dundi.c.

Referenced by set_config().

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

int tos = 0 [static]

Definition at line 115 of file pbx_dundi.c.


Generated on Fri Aug 24 02:27:09 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1