Tue Sep 30 01:20:02 2008

Asterisk developer's documentation


pbx_dundi.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <zlib.h>
#include <sys/signal.h>
#include <pthread.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/md5.h"
#include "asterisk/dundi.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/utils.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/aes.h"
#include "dundi-parser.h"

Include dependency graph for pbx_dundi.c:

Go to the source code of this file.

Data Structures

struct  dundi_hint_metadata
struct  dundi_mapping
struct  dundi_packet
struct  dundi_peer
struct  dundi_precache_queue
struct  dundi_query_state
struct  dundi_request
struct  dundi_transaction
struct  permission

Defines

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)
#define DUNDI_MODEL_INBOUND   (1 << 0)
#define DUNDI_MODEL_OUTBOUND   (1 << 1)
#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME
#define DUNDI_TIMING_HISTORY   10
#define FLAG_DEAD   (1 << 1)
#define FLAG_ENCRYPT   (1 << 4)
#define FLAG_FINAL   (1 << 2)
#define FLAG_ISQUAL   (1 << 3)
#define FLAG_ISREG   (1 << 0)
#define FLAG_SENDFULLKEY   (1 << 5)
#define FLAG_STOREHIST   (1 << 6)
#define FORMAT   "%-12.12s %-12.12s %02d:%02d:%02d\n"
#define FORMAT   "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT   "%-15s %-15s %-15s %-3.3d %-3.3d\n"
#define FORMAT   "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
#define FORMAT   "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
#define FORMAT2   "%-12.12s %-12.12s %-10.10s\n"
#define FORMAT2   "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
#define FORMAT2   "%-15s %-15s %-15s %-3.3s %-3.3s\n"
#define FORMAT2   "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
#define KEY_IN   1
#define KEY_OUT   0
#define MAX_OPTS   128
#define MAX_PACKET_SIZE   8192
#define MAX_RESULTS   64

Functions

static void abort_request (struct dundi_request *dr)
static int ack_trans (struct dundi_transaction *trans, int iseqno)
static void append_permission (struct permissionlist *permlist, char *s, int allow)
static int append_transaction (struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
static void apply_peer (struct dundi_transaction *trans, struct dundi_peer *p)
static AST_LIST_HEAD_NOLOCK_STATIC (alltrans, dundi_transaction)
static AST_LIST_HEAD_NOLOCK_STATIC (requests, dundi_request)
static AST_LIST_HEAD_NOLOCK_STATIC (mappings, dundi_mapping)
static AST_LIST_HEAD_STATIC (pcq, dundi_precache_queue)
static AST_LIST_HEAD_STATIC (peers, dundi_peer)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Distributed Universal Number Discovery (DUNDi)",.load=load_module,.unload=unload_module,.reload=reload,)
static unsigned long avoid_crc32 (dundi_eid *avoid[])
static void build_iv (unsigned char *iv)
static void build_mapping (char *name, char *value)
static void build_peer (dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
static void build_secret (char *secret, int seclen)
static void build_transactions (struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
static int cache_lookup (struct dundi_request *req, dundi_eid *peer_eid, unsigned long crc32, int *lowexpiration)
static int cache_lookup_internal (time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
static int cache_save (dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
static int cache_save_hint (dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
static void cancel_request (struct dundi_request *dr)
static int check_key (struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, unsigned long keycrc32)
static void check_password (void)
static int check_request (struct dundi_request *dr)
static char * complete_peer_4 (const char *line, const char *word, int pos, int state)
static char * complete_peer_helper (const char *line, const char *word, int pos, int state, int rpos)
static struct dundi_transactioncreate_transaction (struct dundi_peer *p)
static int decrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_decrypt_ctx *dcx)
static void deep_copy_peer (struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
static void destroy_map (struct dundi_mapping *map)
static void destroy_packet (struct dundi_packet *pack, int needfree)
static void destroy_packets (struct packetlist *p)
static void destroy_peer (struct dundi_peer *peer)
static void destroy_permissions (struct permissionlist *permlist)
static void destroy_trans (struct dundi_transaction *trans, int fromtimeout)
static int discover_transactions (struct dundi_request *dr)
static int do_autokill (const void *data)
static int do_qualify (const void *data)
static int do_register (const void *data)
static int do_register_expire (const void *data)
static int dundi_ack (struct dundi_transaction *trans, int final)
static int dundi_answer_entity (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_answer_query (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static void dundi_debug_output (const char *data)
static struct dundi_hdrdundi_decrypt (struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
static int dundi_discover (struct dundi_transaction *trans)
static int dundi_do_debug (int fd, int argc, char *argv[])
static int dundi_do_lookup (int fd, int argc, char *argv[])
static int dundi_do_precache (int fd, int argc, char *argv[])
static int dundi_do_query (int fd, int argc, char *argv[])
static int dundi_do_store_history (int fd, int argc, char *argv[])
static int dundi_encrypt (struct dundi_transaction *trans, struct dundi_packet *pack)
static void dundi_error_output (const char *data)
static int dundi_exec (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_flush (int fd, int argc, char *argv[])
static int dundi_helper (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag)
static void dundi_ie_append_eid_appropriately (struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us)
int dundi_lookup (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass)
 Lookup the given number in the given dundi context (or e164 if unspecified) using the given callerid (if specified) and return up to maxret results in the array specified. returns the number of results found or -1 on a hangup of teh channel.
static int dundi_lookup_internal (struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[])
static int dundi_lookup_local (struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
static void * dundi_lookup_thread (void *data)
static int dundi_matchmore (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
static int dundi_no_debug (int fd, int argc, char *argv[])
static int dundi_no_store_history (int fd, int argc, char *argv[])
int dundi_precache (const char *context, const char *number)
 Pre-cache to push upstream peers.
static void dundi_precache_full (void)
static int dundi_precache_internal (const char *context, const char *number, int ttl, dundi_eid *avoids[])
static void * dundi_precache_thread (void *data)
static int dundi_prop_precache (struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
static int dundi_query (struct dundi_transaction *trans)
int dundi_query_eid (struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid)
 Retrieve information on a specific EID.
static int dundi_query_eid_internal (struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[])
static void * dundi_query_thread (void *data)
static void dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin)
static int dundi_rexmit (const void *data)
static int dundi_send (struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
static int dundi_show_entityid (int fd, int argc, char *argv[])
static int dundi_show_mappings (int fd, int argc, char *argv[])
static int dundi_show_peer (int fd, int argc, char *argv[])
static int dundi_show_peers (int fd, int argc, char *argv[])
static int dundi_show_precache (int fd, int argc, char *argv[])
static int dundi_show_requests (int fd, int argc, char *argv[])
static int dundi_show_trans (int fd, int argc, char *argv[])
static int dundi_xmit (struct dundi_packet *pack)
static int dundifunc_read (struct ast_channel *chan, char *cmd, char *num, char *buf, size_t len)
static int encrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_encrypt_ctx *ecx)
static struct dundi_peerfind_peer (dundi_eid *eid)
static struct dundi_transactionfind_transaction (struct dundi_hdr *hdr, struct sockaddr_in *sin)
static int get_trans_id (void)
static int handle_command_response (struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
static int handle_frame (struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)
static int has_permission (struct permissionlist *permlist, char *cont)
static int load_module (void)
static void load_password (void)
static void mark_mappings (void)
static void mark_peers (void)
static char * model2str (int model)
static void * network_thread (void *ignore)
static int optimize_transactions (struct dundi_request *dr, int order)
static void populate_addr (struct dundi_peer *peer, dundi_eid *eid)
static int precache_trans (struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
static int precache_transactions (struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
static void * process_precache (void *ign)
static void prune_mappings (void)
static void prune_peers (void)
static void qualify_peer (struct dundi_peer *peer, int schedonly)
static int query_transactions (struct dundi_request *dr)
static int register_request (struct dundi_request *dr, struct dundi_request **pending)
static int reload (void)
static void reschedule_precache (const char *number, const char *context, int expiration)
static int rescomp (const void *a, const void *b)
static void reset_global_eid (void)
static int reset_transaction (struct dundi_transaction *trans)
static void save_secret (const char *newkey, const char *oldkey)
static int set_config (char *config_file, struct sockaddr_in *sin)
static int socket_read (int *id, int fd, short events, void *cbdata)
static void sort_results (struct dundi_result *results, int count)
static int start_network_thread (void)
static int str2tech (char *str)
static char * tech2str (int tech)
static int unload_module (void)
static void unregister_request (struct dundi_request *dr)
static int update_key (struct dundi_peer *peer)

Variables

static struct dundi_peerany_peer
 Wildcard peer.
static int authdebug = 0
static struct ast_cli_entry cli_dundi []
static char country [80]
static char cursecret [80]
static char debug_usage []
static int default_expiration = 60
static char dept [80]
static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME
static struct ast_custom_function dundi_function
static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE
static int dundi_shutdown = 0
static struct ast_switch dundi_switch
static int dundi_ttl = DUNDI_DEFAULT_TTL
static int dundidebug = 0
static char email [80]
static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }
static char flush_usage []
static int global_autokilltimeout = 0
static dundi_eid global_eid
static int global_storehistory = 0
static struct io_contextio
static char ipaddr [80]
static char locality [80]
static char lookup_usage []
static int netsocket = -1
static pthread_t netthreadid = AST_PTHREADT_NULL
static char no_debug_usage []
static char no_store_history_usage []
static char org [80]
static char phone [80]
static char precache_usage []
static pthread_t precachethreadid = AST_PTHREADT_NULL
static char query_usage []
static time_t rotatetime
static struct sched_contextsched
static char secretpath [80]
static char show_entityid_usage []
static char show_mappings_usage []
static char show_peer_usage []
static char show_peers_usage []
static char show_precache_usage []
static char show_requests_usage []
static char show_trans_usage []
static char stateprov [80]
static char store_history_usage []
static int tos = 0


Detailed Description

Distributed Universal Number Discovery (DUNDi).

Definition in file pbx_dundi.c.


Define Documentation

#define DUNDI_FLAG_INTERNAL_NOPARTIAL   (1 << 17)

Definition at line 98 of file pbx_dundi.c.

Referenced by build_mapping(), and dundi_lookup_local().

#define DUNDI_MODEL_INBOUND   (1 << 0)

Definition at line 83 of file pbx_dundi.c.

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

#define DUNDI_MODEL_OUTBOUND   (1 << 1)

Definition at line 84 of file pbx_dundi.c.

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

#define DUNDI_MODEL_SYMMETRIC   (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)

Definition at line 85 of file pbx_dundi.c.

Referenced by build_peer(), and model2str().

#define DUNDI_SECRET_TIME   DUNDI_DEFAULT_CACHE_TIME

Definition at line 103 of file pbx_dundi.c.

Referenced by load_password(), and save_secret().

#define DUNDI_TIMING_HISTORY   10

Keep times of last 10 lookups

Definition at line 88 of file pbx_dundi.c.

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

#define FLAG_DEAD   (1 << 1)

Transaction is dead

Definition at line 91 of file pbx_dundi.c.

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

#define FLAG_ENCRYPT   (1 << 4)

Transaction is encrypted wiht ECX/DCX

Definition at line 94 of file pbx_dundi.c.

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

#define FLAG_FINAL   (1 << 2)

Transaction has final message sent

Definition at line 92 of file pbx_dundi.c.

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

#define FLAG_ISQUAL   (1 << 3)

Transaction is a qualification

Definition at line 93 of file pbx_dundi.c.

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

#define FLAG_ISREG   (1 << 0)

Transaction is register request

Definition at line 90 of file pbx_dundi.c.

Referenced by destroy_trans(), and do_register().

#define FLAG_SENDFULLKEY   (1 << 5)

Send full key on transaction

Definition at line 95 of file pbx_dundi.c.

Referenced by create_transaction(), dundi_encrypt(), and handle_command_response().

#define FLAG_STOREHIST   (1 << 6)

Record historic performance

Definition at line 96 of file pbx_dundi.c.

Referenced by create_transaction(), and destroy_trans().

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

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

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

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

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

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

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

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

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

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

#define KEY_IN   1

Definition at line 107 of file pbx_dundi.c.

#define KEY_OUT   0

Definition at line 106 of file pbx_dundi.c.

#define MAX_OPTS   128

Definition at line 3940 of file pbx_dundi.c.

Referenced by build_mapping().

#define MAX_PACKET_SIZE   8192

Definition at line 81 of file pbx_dundi.c.

Referenced by handle_command_response(), and socket_read().

#define MAX_RESULTS   64

Definition at line 79 of file pbx_dundi.c.


Function Documentation

static void abort_request ( struct dundi_request dr  )  [static]

Definition at line 3343 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

03344 {
03345    struct dundi_transaction *trans;
03346 
03347    AST_LIST_LOCK(&peers);
03348    while ((trans = AST_LIST_FIRST(&dr->trans))) {
03349       /* This will remove the transaction from the list */
03350       destroy_trans(trans, 0);
03351    }
03352    AST_LIST_UNLOCK(&peers);
03353 }

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

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

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

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

Definition at line 3927 of file pbx_dundi.c.

References ast_calloc, and AST_LIST_INSERT_TAIL.

Referenced by build_peer().

03928 {
03929    struct permission *perm;
03930 
03931    if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
03932       return;
03933 
03934    strcpy(perm->name, s);
03935    perm->allow = allow;
03936 
03937    AST_LIST_INSERT_TAIL(permlist, perm, list);
03938 }

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

Definition at line 3300 of file pbx_dundi.c.

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

Referenced by build_transactions().

03301 {
03302    struct dundi_transaction *trans;
03303    int x;
03304    char eid_str[20];
03305    char eid_str2[20];
03306 
03307    /* Ignore if not registered */
03308    if (!p->addr.sin_addr.s_addr)
03309       return 0;
03310    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
03311       return 0;
03312    if (ast_strlen_zero(dr->number))
03313       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);
03314    else
03315       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);
03316    trans = create_transaction(p);
03317    if (!trans)
03318       return -1;
03319    trans->parent = dr;
03320    trans->ttl = ttl;
03321    for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
03322       trans->eids[x] = *avoid[x];
03323    trans->eidcount = x;
03324    AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
03325    
03326    return 0;
03327 }

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

Definition at line 1251 of file pbx_dundi.c.

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

Referenced by create_transaction(), and handle_command_response().

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

static AST_LIST_HEAD_NOLOCK_STATIC ( alltrans  ,
dundi_transaction   
) [static]

static AST_LIST_HEAD_NOLOCK_STATIC ( requests  ,
dundi_request   
) [static]

static AST_LIST_HEAD_NOLOCK_STATIC ( mappings  ,
dundi_mapping   
) [static]

static AST_LIST_HEAD_STATIC ( pcq  ,
dundi_precache_queue   
) [static]

static AST_LIST_HEAD_STATIC ( peers  ,
dundi_peer   
) [static]

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

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

Definition at line 3464 of file pbx_dundi.c.

References dundi_request::crc32.

Referenced by dundi_lookup_internal().

03465 {
03466    /* Idea is that we're calculating a checksum which is independent of
03467       the order that the EID's are listed in */
03468    unsigned long acrc32 = 0;
03469    int x;
03470    for (x=0;avoid[x];x++) {
03471       /* Order doesn't matter */
03472       if (avoid[x+1]) {
03473          acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
03474       }
03475    }
03476    return acrc32;
03477 }

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

Definition at line 501 of file pbx_dundi.c.

References ast_random().

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

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

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

Definition at line 3942 of file pbx_dundi.c.

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

Referenced by set_config().

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

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

Definition at line 4093 of file pbx_dundi.c.

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

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

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

Definition at line 2043 of file pbx_dundi.c.

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

Referenced by check_password(), and load_password().

02044 {
02045    unsigned char tmp[16];
02046    char *s;
02047    build_iv(tmp);
02048    secret[0] = '\0';
02049    ast_base64encode(secret, tmp, sizeof(tmp), seclen);
02050    /* Eliminate potential bad characters */
02051    while((s = strchr(secret, ';'))) *s = '+';
02052    while((s = strchr(secret, '/'))) *s = '+';
02053    while((s = strchr(secret, ':'))) *s = '+';
02054    while((s = strchr(secret, '@'))) *s = '+';
02055 }

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

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

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

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

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

Definition at line 1199 of file pbx_dundi.c.

References cache_lookup_internal(), dundi_request::dcontext, dundi_eid_to_str(), dundi_eid_to_str_short(), dundi_hint_metadata::exten, dundi_request::hmd, dundi_request::number, dundi_request::respcount, and dundi_request::root_eid.

Referenced by build_transactions().

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

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

Definition at line 1127 of file pbx_dundi.c.

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

Referenced by cache_lookup().

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

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

Definition at line 846 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

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

Definition at line 811 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache(), and handle_command_response().

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

static void cancel_request ( struct dundi_request dr  )  [static]

Definition at line 3329 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal(), and dundi_precache_internal().

03330 {
03331    struct dundi_transaction *trans;
03332 
03333    AST_LIST_LOCK(&peers);
03334    while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
03335       /* Orphan transaction from request */
03336       trans->parent = NULL;
03337       /* Send final cancel */
03338       dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
03339    }
03340    AST_LIST_UNLOCK(&peers);
03341 }

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

Definition at line 1450 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static void check_password ( void   )  [static]

Definition at line 2110 of file pbx_dundi.c.

References build_secret(), and save_secret().

Referenced by network_thread().

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

static int check_request ( struct dundi_request dr  )  [static]

Definition at line 3450 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by dundi_lookup_internal().

03451 {
03452    struct dundi_request *cur;
03453 
03454    AST_LIST_LOCK(&peers);
03455    AST_LIST_TRAVERSE(&requests, cur, list) {
03456       if (cur == dr)
03457          break;
03458    }
03459    AST_LIST_UNLOCK(&peers);
03460    
03461    return cur ? 1 : 0;
03462 }

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

Definition at line 2302 of file pbx_dundi.c.

References complete_peer_helper().

02303 {
02304    return complete_peer_helper(line, word, pos, state, 3);
02305 }

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

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

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

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

Definition at line 2810 of file pbx_dundi.c.

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

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

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

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

Definition at line 1342 of file pbx_dundi.c.

References aes_decrypt().

Referenced by dundi_decrypt().

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

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

Definition at line 1504 of file pbx_dundi.c.

References ast_calloc, AST_LIST_INSERT_HEAD, and AST_LIST_TRAVERSE.

Referenced by handle_command_response().

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

static void destroy_map ( struct dundi_mapping map  )  [static]

Definition at line 3892 of file pbx_dundi.c.

References free.

Referenced by prune_mappings().

03893 {
03894    free(map);
03895 }

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

Definition at line 2856 of file pbx_dundi.c.

References AST_LIST_REMOVE, AST_SCHED_DEL, and free.

Referenced by ack_trans().

02857 {
02858    if (pack->parent)
02859       AST_LIST_REMOVE(&pack->parent->packets, pack, list);
02860    AST_SCHED_DEL(sched, pack->retransid);
02861    if (needfree)
02862       free(pack);
02863 }

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

Definition at line 1942 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, AST_SCHED_DEL, and free.

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

01943 {
01944    struct dundi_packet *pack;
01945    
01946    while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
01947       AST_SCHED_DEL(sched, pack->retransid);
01948       free(pack);
01949    }
01950 }

static void destroy_peer ( struct dundi_peer peer  )  [static]

Definition at line 3881 of file pbx_dundi.c.

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

Referenced by prune_peers().

03882 {
03883    AST_SCHED_DEL(sched, peer->registerid);
03884    if (peer->regtrans)
03885       destroy_trans(peer->regtrans, 0);
03886    AST_SCHED_DEL(sched, peer->qualifyid);
03887    destroy_permissions(&peer->permit);
03888    destroy_permissions(&peer->include);
03889    free(peer);
03890 }

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

Definition at line 3873 of file pbx_dundi.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by build_peer(), and destroy_peer().

03874 {
03875    struct permission *perm;
03876 
03877    while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
03878       free(perm);
03879 }

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

Definition at line 2865 of file pbx_dundi.c.

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

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

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

static int discover_transactions ( struct dundi_request dr  )  [static]

Definition at line 3185 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

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

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

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

03041 {
03042    struct dundi_transaction *trans = (struct dundi_transaction *)data;
03043    char eid_str[20];
03044    ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 
03045       dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
03046    trans->autokillid = -1;
03047    destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
03048    return 0;
03049 }

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

Definition at line 4038 of file pbx_dundi.c.

References qualify_peer().

Referenced by qualify_peer().

04039 {
04040    struct dundi_peer *peer = (struct dundi_peer *)data;
04041    peer->qualifyid = -1;
04042    qualify_peer(peer, 0);
04043    return 0;
04044 }

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

Definition at line 4012 of file pbx_dundi.c.

References ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), destroy_trans(), DUNDI_COMMAND_REGREQ, DUNDI_DEFAULT_VERSION, dundi_eid_to_str(), dundi_ie_append_eid(), dundi_ie_append_short(), DUNDI_IE_EID, DUNDI_IE_EXPIRATION, DUNDI_IE_VERSION, dundi_send(), dundi_peer::eid, FLAG_ISREG, LOG_DEBUG, and LOG_NOTICE.

Referenced by build_peer().

04013 {
04014    struct dundi_ie_data ied;
04015    struct dundi_peer *peer = (struct dundi_peer *)data;
04016    char eid_str[20];
04017    char eid_str2[20];
04018    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));
04019    peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
04020    /* Destroy old transaction if there is one */
04021    if (peer->regtrans)
04022       destroy_trans(peer->regtrans, 0);
04023    peer->regtrans = create_transaction(peer);
04024    if (peer->regtrans) {
04025       ast_set_flag(peer->regtrans, FLAG_ISREG);
04026       memset(&ied, 0, sizeof(ied));
04027       dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
04028       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
04029       dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
04030       dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
04031       
04032    } else
04033       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));
04034 
04035    return 0;
04036 }

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

Note:
Called with the peers list already locked

Definition at line 1276 of file pbx_dundi.c.

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

Referenced by handle_command_response(), and populate_addr().

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

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

Definition at line 374 of file pbx_dundi.c.

References DUNDI_COMMAND_ACK, and dundi_send().

Referenced by handle_command_response(), and handle_frame().

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

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

Definition at line 751 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 1039 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 4283 of file pbx_dundi.c.

References DUNDI_FLAG_CANMATCH, and dundi_helper().

04284 {
04285    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
04286 }

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

Definition at line 278 of file pbx_dundi.c.

References ast_verbose().

Referenced by load_module().

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

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

Definition at line 1359 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_discover ( struct dundi_transaction trans  )  [static]

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

03074 {
03075    struct dundi_ie_data ied;
03076    int x;
03077    if (!trans->parent) {
03078       ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
03079       return -1;
03080    }
03081    memset(&ied, 0, sizeof(ied));
03082    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03083    if (!dundi_eid_zero(&trans->us_eid))
03084       dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
03085    for (x=0;x<trans->eidcount;x++)
03086       dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
03087    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
03088    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03089    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03090    if (trans->parent->cbypass)
03091       dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
03092    if (trans->autokilltimeout)
03093       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03094    return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
03095 }

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

Definition at line 2197 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

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

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

Definition at line 2324 of file pbx_dundi.c.

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

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

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

Definition at line 2365 of file pbx_dundi.c.

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

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

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

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

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

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

Definition at line 2206 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

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

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

Definition at line 1383 of file pbx_dundi.c.

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

Referenced by dundi_send().

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

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

Definition at line 284 of file pbx_dundi.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

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

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

Definition at line 4288 of file pbx_dundi.c.

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

04289 {
04290    struct dundi_result results[MAX_RESULTS];
04291    int res;
04292    int x=0;
04293    char req[1024];
04294    struct ast_app *dial;
04295    
04296    if (!strncasecmp(context, "macro-", 6)) {
04297       if (!chan) {   
04298          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04299          return -1;
04300       }
04301       /* If done as a macro, use macro extension */
04302       if (!strcasecmp(exten, "s")) {
04303          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04304          if (ast_strlen_zero(exten))
04305             exten = chan->macroexten;
04306          if (ast_strlen_zero(exten))
04307             exten = chan->exten;
04308          if (ast_strlen_zero(exten)) { 
04309             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04310             return -1;
04311          }
04312       }
04313       if (ast_strlen_zero(data))
04314          data = "e164";
04315    } else {
04316       if (ast_strlen_zero(data))
04317          data = context;
04318    }
04319    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04320    if (res > 0) {
04321       sort_results(results, res);
04322       for (x=0;x<res;x++) {
04323          if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
04324             if (!--priority)
04325                break;
04326          }
04327       }
04328    }
04329    if (x < res) {
04330       /* Got a hit! */
04331       snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
04332       dial = pbx_findapp("Dial");
04333       if (dial)
04334          res = pbx_exec(chan, dial, req);
04335    } else
04336       res = -1;
04337    return res;
04338 }

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

References DUNDI_FLAG_EXISTS, and dundi_helper().

04279 {
04280    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
04281 }

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

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

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

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

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

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

04240 {
04241    struct dundi_result results[MAX_RESULTS];
04242    int res;
04243    int x;
04244    int found = 0;
04245    if (!strncasecmp(context, "macro-", 6)) {
04246       if (!chan) {   
04247          ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
04248          return -1;
04249       }
04250       /* If done as a macro, use macro extension */
04251       if (!strcasecmp(exten, "s")) {
04252          exten = pbx_builtin_getvar_helper(chan, "ARG1");
04253          if (ast_strlen_zero(exten))
04254             exten = chan->macroexten;
04255          if (ast_strlen_zero(exten))
04256             exten = chan->exten;
04257          if (ast_strlen_zero(exten)) { 
04258             ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
04259             return -1;
04260          }
04261       }
04262       if (ast_strlen_zero(data))
04263          data = "e164";
04264    } else {
04265       if (ast_strlen_zero(data))
04266          data = context;
04267    }
04268    res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
04269    for (x=0;x<res;x++) {
04270       if (ast_test_flag(results + x, flag))
04271          found++;
04272    }
04273    if (found >= priority)
04274       return 1;
04275    return 0;
04276 }

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

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

03052 {
03053    struct dundi_peer *p;
03054    if (!dundi_eid_cmp(eid, us)) {
03055       dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03056       return;
03057    }
03058    AST_LIST_LOCK(&peers);
03059    AST_LIST_TRAVERSE(&peers, p, list) {
03060       if (!dundi_eid_cmp(&p->eid, eid)) {
03061          if (has_permission(&p->include, context))
03062             dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
03063          else
03064             dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03065          break;
03066       }
03067    }
03068    if (!p)
03069       dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
03070    AST_LIST_UNLOCK(&peers);
03071 }

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

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

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

03582 {
03583    struct dundi_hint_metadata hmd;
03584    dundi_eid *avoid[1] = { NULL, };
03585    int direct[1] = { 0, };
03586    int expiration = dundi_cache_time;
03587    memset(&hmd, 0, sizeof(hmd));
03588    hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
03589    return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
03590 }

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

References ast_channel::_softhangup, abort_request(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_waitfor_n_fd(), avoid_crc32(), build_transactions(), cancel_request(), dundi_request::cbypass, check_request(), dundi_request::crc32, dundi_request::dcontext, discover_transactions(), dundi_request::dr, dundi_eid_cmp(), dundi_eid_to_str(), DUNDI_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_DEBUG, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, and unregister_request().

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

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

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

Definition at line 527 of file pbx_dundi.c.

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

Referenced by dundi_lookup_thread(), and precache_trans().

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

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

Definition at line 600 of file pbx_dundi.c.

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

Referenced by dundi_answer_query().

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

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

Definition at line 4340 of file pbx_dundi.c.

References DUNDI_FLAG_MATCHMORE, and dundi_helper().

04341 {
04342    return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
04343 }

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

Definition at line 2248 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02249 {
02250    if (argc != 3)
02251       return RESULT_SHOWUSAGE;
02252    dundidebug = 0;
02253    ast_cli(fd, "DUNDi Debugging Disabled\n");
02254    return RESULT_SUCCESS;
02255 }

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

Definition at line 2257 of file pbx_dundi.c.

References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02258 {
02259    if (argc != 4)
02260       return RESULT_SHOWUSAGE;
02261    global_storehistory = 0;
02262    ast_cli(fd, "DUNDi History Storage Disabled\n");
02263    return RESULT_SUCCESS;
02264 }

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

Pre-cache to push upstream peers.

Definition at line 3725 of file pbx_dundi.c.

References dundi_precache_internal().

Referenced by dundi_do_precache(), and process_precache().

03726 {
03727    dundi_eid *avoid[1] = { NULL, };
03728    return dundi_precache_internal(context, number, dundi_ttl, avoid);
03729 }

static void dundi_precache_full ( void   )  [static]

Definition at line 3628 of file pbx_dundi.c.

References ast_get_context_name(), ast_get_extension_name(), AST_LIST_TRAVERSE, ast_lock_context(), ast_log(), ast_rdlock_contexts(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_context_extensions(), ast_walk_contexts(), dundi_mapping::dcontext, dundi_mapping::lcontext, LOG_NOTICE, and reschedule_precache().

Referenced by set_config().

03629 {
03630    struct dundi_mapping *cur;
03631    struct ast_context *con;
03632    struct ast_exten *e;
03633 
03634    AST_LIST_TRAVERSE(&mappings, cur, list) {
03635       ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
03636       ast_rdlock_contexts();
03637       con = ast_walk_contexts(NULL);
03638       while (con) {
03639          if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
03640             /* Found the match, now queue them all up */
03641             ast_lock_context(con);
03642             e = ast_walk_context_extensions(con, NULL);
03643             while (e) {
03644                reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
03645                e = ast_walk_context_extensions(con, e);
03646             }
03647             ast_unlock_context(con);
03648          }
03649          con = ast_walk_contexts(con);
03650       }
03651       ast_unlock_contexts();
03652    }
03653 }

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

Definition at line 3655 of file pbx_dundi.c.

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dundi_request::dcontext, dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, dundi_request::expiration, dundi_request::hmd, LOG_DEBUG, LOG_NOTICE, dundi_request::maxcount, dundi_request::number, optimize_transactions(), peers, dundi_request::pfds, precache_transactions(), and reschedule_precache().

Referenced by dundi_precache(), and dundi_precache_thread().

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

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

Definition at line 664 of file pbx_dundi.c.

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

Referenced by dundi_prop_precache().

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

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

Definition at line 887 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

static int dundi_query ( struct dundi_transaction trans  )  [static]

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

03164 {
03165    struct dundi_ie_data ied;
03166    int x;
03167    if (!trans->parent) {
03168       ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
03169       return -1;
03170    }
03171    memset(&ied, 0, sizeof(ied));
03172    dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
03173    if (!dundi_eid_zero(&trans->us_eid))
03174       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
03175    for (x=0;x<trans->eidcount;x++)
03176       dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
03177    dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
03178    dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
03179    dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
03180    if (trans->autokilltimeout)
03181       trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
03182    return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
03183 }

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

Retrieve information on a specific EID.

Definition at line 3778 of file pbx_dundi.c.

References dundi_query_eid_internal().

Referenced by dundi_do_query().

03779 {
03780    dundi_eid *avoid[1] = { NULL, };
03781    struct dundi_hint_metadata hmd;
03782    memset(&hmd, 0, sizeof(hmd));
03783    return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
03784 }

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

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

Referenced by dundi_query_eid(), and dundi_query_thread().

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

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

Definition at line 697 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), ast_test_flag, dundi_query_state::called_context, dundi_query_state::called_number, dundi_entity_info::country, destroy_trans(), DUNDI_COMMAND_EIDRESPONSE, dundi_eid_cmp(), dundi_eid_to_str(), dundi_ie_append_hint(), dundi_ie_append_str(), DUNDI_IE_COUNTRY, DUNDI_IE_DEPARTMENT, DUNDI_IE_EMAIL, DUNDI_IE_HINT, DUNDI_IE_IPADDR, DUNDI_IE_LOCALITY, DUNDI_IE_ORGANIZATION, DUNDI_IE_PHONE, DUNDI_IE_STATE_PROV, dundi_query_eid_internal(), dundi_send(), dundi_query_state::eids, dundi_entity_info::email, dundi_hint_metadata::exten, FLAG_DEAD, dundi_hint_metadata::flags, free, dundi_entity_info::ipaddr, dundi_entity_info::locality, LOG_DEBUG, dundi_entity_info::org, dundi_entity_info::orgunit, peers, dundi_entity_info::phone, dundi_query_state::reqeid, dundi_entity_info::stateprov, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, and dundi_transaction::us_eid.

Referenced by dundi_answer_entity().

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

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

Definition at line 378 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

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

02947 {
02948    struct dundi_packet *pack = (struct dundi_packet *)data;
02949    int res;
02950    AST_LIST_LOCK(&peers);
02951    if (pack->retrans < 1) {
02952       pack->retransid = -1;
02953       if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
02954          ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 
02955             ast_inet_ntoa(pack->parent->addr.sin_addr), 
02956             ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
02957       destroy_trans(pack->parent, 1);
02958       res = 0;
02959    } else {
02960       /* Decrement retransmission, try again */
02961       pack->retrans--;
02962       dundi_xmit(pack);
02963       res = 1;
02964    }
02965    AST_LIST_UNLOCK(&peers);
02966    return res;
02967 }

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

Definition at line 2969 of file pbx_dundi.c.

References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, AST_LIST_INSERT_HEAD, ast_log(), ast_sched_add(), ast_set_flag, ast_test_flag, dundi_transaction::dtrans, DUNDI_COMMAND_ACK, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_FINAL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_DEFAULT_RETRANS, dundi_eid_to_str(), dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, free, dundi_transaction::iseqno, len, LOG_NOTICE, dundi_transaction::oseqno, dundi_transaction::retranstimer, dundi_transaction::strans, and dundi_transaction::them_eid.

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

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

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

Definition at line 2595 of file pbx_dundi.c.

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

02596 {
02597    char eid_str[20];
02598    if (argc != 3)
02599       return RESULT_SHOWUSAGE;
02600    AST_LIST_LOCK(&peers);
02601    dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
02602    AST_LIST_UNLOCK(&peers);
02603    ast_cli(fd, "Global EID for this system is '%s'\n", eid_str);
02604    return RESULT_SUCCESS;
02605 }

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

Definition at line 2629 of file pbx_dundi.c.

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

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

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

Definition at line 2428 of file pbx_dundi.c.

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

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

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

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

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

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

Definition at line 2650 of file pbx_dundi.c.

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

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

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

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

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

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

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

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

static int dundi_xmit ( struct dundi_packet pack  )  [static]

Definition at line 2840 of file pbx_dundi.c.

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

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

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

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

Definition at line 3786 of file pbx_dundi.c.

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

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

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

Definition at line 1326 of file pbx_dundi.c.

References aes_encrypt().

Referenced by dundi_encrypt().

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

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

Definition at line 483 of file pbx_dundi.c.

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

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

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

Definition at line 333 of file pbx_dundi.c.

References dundi_transaction::addr, AST_LIST_TRAVERSE, ast_log(), dundi_hdr::cmdresp, create_transaction(), dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_ENCRYPT, DUNDI_COMMAND_NULL, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, inaddrcmp(), LOG_WARNING, dundi_hdr::strans, and dundi_transaction::strans.

Referenced by handle_frame().

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

static int get_trans_id ( void   )  [static]

Definition at line 448 of file pbx_dundi.c.

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

Referenced by create_transaction(), and reset_transaction().

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

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

Definition at line 1534 of file pbx_dundi.c.

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

Referenced by handle_frame().

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

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

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

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

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

Definition at line 289 of file pbx_dundi.c.

References AST_LIST_TRAVERSE.

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

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

static int load_module ( void   )  [static]

Definition at line 4551 of file pbx_dundi.c.

References ast_cli_register_multiple(), ast_custom_function_register(), ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, ast_register_switch(), ast_verbose(), dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, LOG_WARNING, option_verbose, sched_context_create(), set_config(), start_network_thread(), and VERBOSE_PREFIX_2.

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

static void load_password ( void   )  [static]

Definition at line 2071 of file pbx_dundi.c.

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

Referenced by set_config().

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

static void mark_mappings ( void   )  [static]

Definition at line 3862 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

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

static void mark_peers ( void   )  [static]

Definition at line 3852 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and peers.

Referenced by set_config(), and unload_module().

03853 {
03854    struct dundi_peer *peer;
03855    AST_LIST_LOCK(&peers);
03856    AST_LIST_TRAVERSE(&peers, peer, list) {
03857       peer->dead = 1;
03858    }
03859    AST_LIST_UNLOCK(&peers);
03860 }

static char* model2str ( int  model  )  [static]

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

02267 {
02268    switch(model) {
02269    case DUNDI_MODEL_INBOUND:
02270       return "Inbound";
02271    case DUNDI_MODEL_OUTBOUND:
02272       return "Outbound";
02273    case DUNDI_MODEL_SYMMETRIC:
02274       return "Symmetric";
02275    default:
02276       return "Unknown";
02277    }
02278 }

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

Definition at line 2127 of file pbx_dundi.c.

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

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

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

Definition at line 3244 of file pbx_dundi.c.

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

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

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

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

Definition at line 4069 of file pbx_dundi.c.

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

Referenced by build_peer().

04070 {
04071    char data[256];
04072    char *c;
04073    int port, expire;
04074    char eid_str[20];
04075    dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
04076    if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
04077       c = strchr(data, ':');
04078       if (c) {
04079          *c = '\0';
04080          c++;
04081          if (sscanf(c, "%d:%d", &port, &expire) == 2) {
04082             /* Got it! */
04083             inet_aton(data, &peer->addr.sin_addr);
04084             peer->addr.sin_family = AF_INET;
04085             peer->addr.sin_port = htons(port);
04086             peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
04087          }
04088       }
04089    }
04090 }

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

Definition at line 3097 of file pbx_dundi.c.

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

Referenced by precache_transactions().

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

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

Definition at line 3196 of file pbx_dundi.c.

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

Referenced by dundi_precache_internal().

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

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

Definition at line 2153 of file pbx_dundi.c.

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

Referenced by start_network_thread().

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

static void prune_mappings ( void   )  [static]

Definition at line 3912 of file pbx_dundi.c.

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

Referenced by set_config(), and unload_module().

03913 {
03914    struct dundi_mapping *map;
03915 
03916    AST_LIST_LOCK(&peers);
03917    AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
03918       if (map->dead) {
03919          AST_LIST_REMOVE_CURRENT(&mappings, list);
03920          destroy_map(map);
03921       }
03922    }
03923    AST_LIST_TRAVERSE_SAFE_END
03924    AST_LIST_UNLOCK(&peers);
03925 }

static void prune_peers ( void   )  [static]

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

03898 {
03899    struct dundi_peer *peer;
03900 
03901    AST_LIST_LOCK(&peers);
03902    AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
03903       if (peer->dead) {
03904          AST_LIST_REMOVE_CURRENT(&peers, list);
03905          destroy_peer(peer);
03906       }
03907    }
03908    AST_LIST_TRAVERSE_SAFE_END
03909    AST_LIST_UNLOCK(&peers);
03910 }

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

Definition at line 4046 of file pbx_dundi.c.

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

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

04047 {
04048    int when;
04049    AST_SCHED_DEL(sched, peer->qualifyid);
04050    if (peer->qualtrans)
04051       destroy_trans(peer->qualtrans, 0);
04052    peer->qualtrans = NULL;
04053    if (peer->maxms > 0) {
04054       when = 60000;
04055       if (peer->lastms < 0)
04056          when = 10000;
04057       if (schedonly)
04058          when = 5000;
04059       peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
04060       if (!schedonly)
04061          peer->qualtrans = create_transaction(peer);
04062       if (peer->qualtrans) {
04063          peer->qualtx = ast_tvnow();
04064          ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
04065          dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
04066       }
04067    }
04068 }

static int query_transactions ( struct dundi_request dr  )  [static]

Definition at line 3231 of file pbx_dundi.c.

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

Referenced by dundi_query_eid_internal().

03232 {
03233    struct dundi_transaction *trans;
03234 
03235    AST_LIST_LOCK(&peers);
03236    AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
03237       dundi_query(trans);
03238    }
03239    AST_LIST_UNLOCK(&peers);
03240 
03241    return 0;
03242 }

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

Definition at line 3412 of file pbx_dundi.c.

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

Referenced by dundi_lookup_internal().

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

static int reload ( void   )  [static]

Definition at line 4544 of file pbx_dundi.c.

References set_config().

04545 {
04546    struct sockaddr_in sin;
04547    set_config("dundi.conf",&sin);
04548    return 0;
04549 }

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

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

03593 {
03594    int len;
03595    struct dundi_precache_queue *qe, *prev;
03596 
03597    AST_LIST_LOCK(&pcq);
03598    AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
03599       if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
03600          AST_LIST_REMOVE_CURRENT(&pcq, list);
03601          break;
03602       }
03603    }
03604    AST_LIST_TRAVERSE_SAFE_END
03605    if (!qe) {
03606       len = sizeof(*qe);
03607       len += strlen(number) + 1;
03608       len += strlen(context) + 1;
03609       if (!(qe = ast_calloc(1, len))) {
03610          AST_LIST_UNLOCK(&pcq);
03611          return;
03612       }
03613       strcpy(qe->number, number);
03614       qe->context = qe->number + strlen(number) + 1;
03615       strcpy(qe->context, context);
03616    }
03617    time(&qe->expiration);
03618    qe->expiration += expiration;
03619    if ((prev = AST_LIST_FIRST(&pcq))) {
03620       while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
03621          prev = AST_LIST_NEXT(prev, list);
03622       AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
03623    } else
03624       AST_LIST_INSERT_HEAD(&pcq, qe, list);
03625    AST_LIST_UNLOCK(&pcq);
03626 }

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

Definition at line 2307 of file pbx_dundi.c.

References dundi_result::weight.

Referenced by sort_results().

02308 {
02309    const struct dundi_result *resa, *resb;
02310    resa = a;
02311    resb = b;
02312    if (resa->weight < resb->weight)
02313       return -1;
02314    if (resa->weight > resb->weight)
02315       return 1;
02316    return 0;
02317 }

static void reset_global_eid ( void   )  [static]

Definition at line 403 of file pbx_dundi.c.

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

Referenced by set_config().

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

static int reset_transaction ( struct dundi_transaction trans  )  [static]

Definition at line 467 of file pbx_dundi.c.

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

Referenced by handle_command_response().

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

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

Definition at line 2058 of file pbx_dundi.c.

References ast_db_put(), and DUNDI_SECRET_TIME.

Referenced by check_password(), and load_password().

02059 {
02060    char tmp[256];
02061    if (oldkey)
02062       snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
02063    else
02064       snprintf(tmp, sizeof(tmp), "%s", newkey);
02065    rotatetime = time(NULL) + DUNDI_SECRET_TIME;
02066    ast_db_put(secretpath, "secret", tmp);
02067    snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
02068    ast_db_put(secretpath, "secretexpiry", tmp);
02069 }

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

Definition at line 4355 of file pbx_dundi.c.

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

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

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

Definition at line 2015 of file pbx_dundi.c.

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

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

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

Definition at line 2319 of file pbx_dundi.c.

References rescomp().

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

02320 {
02321    qsort(results, count, sizeof(results[0]), rescomp);
02322 }

static int start_network_thread ( void   )  [static]

Definition at line 2190 of file pbx_dundi.c.

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

02191 {
02192    ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
02193    ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
02194    return 0;
02195 }

static int str2tech ( char *  str  )  [static]

Definition at line 318 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.

Referenced by build_mapping().

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

static char* tech2str ( int  tech  )  [static]

Definition at line 302 of file pbx_dundi.c.

References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, DUNDI_PROTO_NONE, and DUNDI_PROTO_SIP.

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

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

static int unload_module ( void   )  [static]

Definition at line 4513 of file pbx_dundi.c.

References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_module_user_hangup_all, AST_PTHREADT_NULL, ast_unregister_switch(), io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), and sched_context_destroy().

04514 {
04515    pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid;
04516    ast_module_user_hangup_all();
04517 
04518    /* Stop all currently running threads */
04519    dundi_shutdown = 1;
04520    if (previous_netthreadid != AST_PTHREADT_NULL) {
04521       pthread_kill(previous_netthreadid, SIGURG);
04522       pthread_join(previous_netthreadid, NULL);
04523    }
04524    if (previous_precachethreadid != AST_PTHREADT_NULL) {
04525       pthread_kill(previous_precachethreadid, SIGURG);
04526       pthread_join(previous_precachethreadid, NULL);
04527    }
04528 
04529    ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
04530    ast_unregister_switch(&dundi_switch);
04531    ast_custom_function_unregister(&dundi_function);
04532    close(netsocket);
04533    io_context_destroy(io);
04534    sched_context_destroy(sched);
04535 
04536    mark_mappings();
04537    prune_mappings();
04538    mark_peers();
04539    prune_peers();
04540 
04541    return 0;
04542 }

static void unregister_request ( struct dundi_request dr  )  [static]

Definition at line 3443 of file pbx_dundi.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and peers.

Referenced by dundi_lookup_internal().

03444 {
03445    AST_LIST_LOCK(&peers);
03446    AST_LIST_REMOVE(&requests, dr, list);
03447    AST_LIST_UNLOCK(&peers);
03448 }

static int update_key ( struct dundi_peer peer  )  [static]

Definition at line 1287 of file pbx_dundi.c.

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

Referenced by dundi_encrypt().

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


Variable Documentation

struct dundi_peer* any_peer [static]

Wildcard peer.

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

Definition at line 274 of file pbx_dundi.c.

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

int authdebug = 0 [static]

Definition at line 116 of file pbx_dundi.c.

struct ast_cli_entry cli_dundi[] [static]

Definition at line 2748 of file pbx_dundi.c.

char country[80] [static]

Definition at line 128 of file pbx_dundi.c.

Referenced by ind_load_module().

char cursecret[80] [static]

Definition at line 132 of file pbx_dundi.c.

char debug_usage[] [static]

Initial value:

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

Definition at line 2678 of file pbx_dundi.c.

int default_expiration = 60 [static]

Definition at line 122 of file pbx_dundi.c.

char dept[80] [static]

Definition at line 124 of file pbx_dundi.c.

int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static]

Definition at line 119 of file pbx_dundi.c.

int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static]

Definition at line 118 of file pbx_dundi.c.

int dundi_shutdown = 0 [static]

Definition at line 136 of file pbx_dundi.c.

struct ast_switch dundi_switch [static]

Definition at line 4345 of file pbx_dundi.c.

int dundi_ttl = DUNDI_DEFAULT_TTL [static]

Definition at line 117 of file pbx_dundi.c.

int dundidebug = 0 [static]

Definition at line 115 of file pbx_dundi.c.

char email[80] [static]

Definition at line 129 of file pbx_dundi.c.

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

Definition at line 135 of file pbx_dundi.c.

char flush_usage[] [static]

Initial value:

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

Definition at line 2742 of file pbx_dundi.c.

int global_autokilltimeout = 0 [static]

Definition at line 120 of file pbx_dundi.c.

Definition at line 121 of file pbx_dundi.c.

int global_storehistory = 0 [static]

Definition at line 123 of file pbx_dundi.c.

struct io_context* io [static]

Definition at line 109 of file pbx_dundi.c.

char ipaddr[80] [static]

Definition at line 133 of file pbx_dundi.c.

Referenced by realtime_update_peer().

char locality[80] [static]

Definition at line 126 of file pbx_dundi.c.

char lookup_usage[] [static]

Initial value:

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

Definition at line 2724 of file pbx_dundi.c.

int netsocket = -1 [static]

Definition at line 111 of file pbx_dundi.c.

Referenced by ast_netsock_bindaddr(), and handle_error().

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 112 of file pbx_dundi.c.

char no_debug_usage[] [static]

Initial value:

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

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

char org[80] [static]

Definition at line 125 of file pbx_dundi.c.

Referenced by calc_crc().

char phone[80] [static]

Definition at line 130 of file pbx_dundi.c.

Referenced by privacy_exec().

char precache_usage[] [static]

Initial value:

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

Definition at line 2730 of file pbx_dundi.c.

pthread_t precachethreadid = AST_PTHREADT_NULL [static]

Definition at line 113 of file pbx_dundi.c.

char query_usage[] [static]

Initial value:

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

Definition at line 2736 of file pbx_dundi.c.

time_t rotatetime [static]

Definition at line 134 of file pbx_dundi.c.

struct sched_context* sched [static]

Definition at line 110 of file pbx_dundi.c.

char secretpath[80] [static]

Definition at line 131 of file pbx_dundi.c.

char show_entityid_usage[] [static]

Initial value:

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

Definition at line 2712 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 2704 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 2716 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 2696 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 2708 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 2720 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 2700 of file pbx_dundi.c.

char stateprov[80] [static]

Definition at line 127 of file pbx_dundi.c.

char store_history_usage[] [static]

Initial value:

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

Definition at line 2686 of file pbx_dundi.c.

int tos = 0 [static]

Definition at line 114 of file pbx_dundi.c.


Generated on Tue Sep 30 01:20:02 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.6