Distributed Universal Number Discovery (DUNDi). More...
#include "asterisk.h"
#include "asterisk/network.h"
#include <sys/ioctl.h>
#include <zlib.h>
#include <sys/signal.h>
#include <pthread.h>
#include <net/if.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/config.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/netsock.h"
#include "asterisk/crypto.h"
#include "asterisk/astdb.h"
#include "asterisk/acl.h"
#include "asterisk/app.h"
#include "dundi-parser.h"
Go to the source code of this file.
Data Structures | |
struct | alltrans |
struct | dundi_hint_metadata |
struct | dundi_mapping |
struct | dundi_packet |
struct | dundi_peer |
struct | dundi_precache_queue |
struct | dundi_query_state |
struct | dundi_request |
struct | dundi_result_datastore |
struct | dundi_transaction |
struct | mappings |
struct | packetlist |
struct | pcq |
struct | peers |
struct | permission |
struct | permissionlist |
struct | requests |
Defines | |
#define | DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17) |
#define | DUNDI_MODEL_INBOUND (1 << 0) |
#define | DUNDI_MODEL_OUTBOUND (1 << 1) |
#define | DUNDI_MODEL_SYMMETRIC (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND) |
#define | DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME |
#define | DUNDI_TIMING_HISTORY 10 |
#define | FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n" |
#define | FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
#define | FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n" |
#define | FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" |
#define | FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n" |
#define | FORMAT2 "%-12.12s %-12.12s %-10.10s\n" |
#define | FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
#define | FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" |
#define | FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" |
#define | FORMAT2 "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n" |
#define | MAX_OPTS 128 |
#define | MAX_PACKET_SIZE 8192 |
#define | MAX_RESULTS 64 |
#define | MAX_WEIGHT 59999 |
Enumerations | |
enum | { FLAG_ISREG = (1 << 0), FLAG_DEAD = (1 << 1), FLAG_FINAL = (1 << 2), FLAG_ISQUAL = (1 << 3), FLAG_ENCRYPT = (1 << 4), FLAG_SENDFULLKEY = (1 << 5), FLAG_STOREHIST = (1 << 6) } |
enum | { OPT_BYPASS_CACHE = (1 << 0) } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | abort_request (struct dundi_request *dr) |
static int | ack_trans (struct dundi_transaction *trans, int iseqno) |
static void | append_permission (struct permissionlist *permlist, const char *s, int allow) |
static int | append_transaction (struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[]) |
static void | apply_peer (struct dundi_transaction *trans, struct dundi_peer *p) |
static unsigned long | avoid_crc32 (dundi_eid *avoid[]) |
static void | build_iv (unsigned char *iv) |
static void | build_mapping (const char *name, const char *value) |
static void | build_peer (dundi_eid *eid, struct ast_variable *v, int *globalpcmode) |
static void | build_secret (char *secret, int seclen) |
static void | build_transactions (struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[]) |
static int | cache_lookup (struct dundi_request *req, dundi_eid *peer_eid, uint32_t crc32, int *lowexpiration) |
static int | cache_lookup_internal (time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration) |
static int | cache_save (dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push) |
static int | cache_save_hint (dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration) |
static void | cancel_request (struct dundi_request *dr) |
static int | check_key (struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, uint32_t keycrc32) |
static void | check_password (void) |
static int | check_request (struct dundi_request *dr) |
static char * | complete_peer_helper (const char *line, const char *word, int pos, int state, int rpos) |
static struct dundi_transaction * | create_transaction (struct dundi_peer *p) |
static int | decrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_decrypt_key *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 void | drds_destroy (struct dundi_result_datastore *drds) |
static void | drds_destroy_cb (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_hdr * | dundi_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 char * | dundi_do_lookup (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_do_precache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_do_query (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
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 char * | dundi_flush (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
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. Lookup number in a given dundi context (if unspecified use e164), the given callerid (if specified) and return up to maxret results in the array specified. | |
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) |
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 int | dundi_query_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static void * | dundi_query_thread (void *data) |
static void | dundi_reject (struct dundi_hdr *h, struct sockaddr_in *sin) |
static int | dundi_result_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
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 char * | dundi_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_entityid (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_mappings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_peer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_peers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_precache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_requests (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_show_trans (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | dundi_store_history (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static int | dundi_xmit (struct dundi_packet *pack) |
static int | dundifunc_read (struct ast_channel *chan, const char *cmd, char *num, char *buf, size_t len) |
static int | encrypt_memcpy (unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_encrypt_key *ecx) |
static struct dundi_peer * | find_peer (dundi_eid *eid) |
static struct dundi_transaction * | find_transaction (struct dundi_hdr *hdr, struct sockaddr_in *sin) |
static int | get_mapping_weight (struct dundi_mapping *map) |
static int | get_trans_id (void) |
static int | handle_command_response (struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted) |
static int | handle_frame (struct dundi_hdr *h, struct sockaddr_in *sin, int datalen) |
static int | has_permission (struct permissionlist *permlist, char *cont) |
static int | load_module (void) |
static void | load_password (void) |
static void | mark_mappings (void) |
static void | mark_peers (void) |
static char * | model2str (int model) |
static void * | network_thread (void *ignore) |
static int | optimize_transactions (struct dundi_request *dr, int order) |
static void | populate_addr (struct dundi_peer *peer, dundi_eid *eid) |
static int | precache_trans (struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers) |
static int | precache_transactions (struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers) |
static void * | process_clearcache (void *ignore) |
static void * | process_precache (void *ign) |
static void | prune_mappings (void) |
static void | prune_peers (void) |
static void | qualify_peer (struct dundi_peer *peer, int schedonly) |
static int | query_transactions (struct dundi_request *dr) |
static int | register_request (struct dundi_request *dr, struct dundi_request **pending) |
static int | reload (void) |
static void | reschedule_precache (const char *number, const char *context, int expiration) |
static int | rescomp (const void *a, const void *b) |
static 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, int reload) |
static int | socket_read (int *id, int fd, short events, void *cbdata) |
static void | sort_results (struct dundi_result *results, int count) |
static int | start_network_thread (void) |
static int | str2tech (char *str) |
static char * | tech2str (int tech) |
static int | unload_module (void) |
static void | unregister_request (struct dundi_request *dr) |
static int | update_key (struct dundi_peer *peer) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Distributed Universal Number Discovery (DUNDi)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .nonoptreq = "res_crypto", } |
static struct dundi_peer * | any_peer |
Wildcard peer. | |
static struct ast_module_info * | ast_module_info = &__mod_info |
static int | authdebug = 0 |
static pthread_t | clearcachethreadid = AST_PTHREADT_NULL |
static struct ast_cli_entry | cli_dundi [] |
static char | country [80] |
static char | cursecret [80] |
static 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 struct ast_custom_function | dundi_query_function |
static struct ast_app_option | dundi_query_opts [128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, } |
static struct ast_datastore_info | dundi_result_datastore_info |
static struct ast_custom_function | dundi_result_function |
static unsigned int | dundi_result_id |
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 int | global_autokilltimeout = 0 |
static dundi_eid | global_eid |
static int | global_storehistory = 0 |
static struct io_context * | io |
static char | ipaddr [80] |
static char | locality [80] |
static int | netsocket = -1 |
static pthread_t | netthreadid = AST_PTHREADT_NULL |
static char | org [80] |
static char | phone [80] |
static pthread_t | precachethreadid = AST_PTHREADT_NULL |
static time_t | rotatetime |
static struct sched_context * | sched |
static char | secretpath [80] |
static char | stateprov [80] |
static unsigned int | tos = 0 |
Distributed Universal Number Discovery (DUNDi).
Definition in file pbx_dundi.c.
#define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17) |
Definition at line 168 of file pbx_dundi.c.
Referenced by build_mapping(), and dundi_lookup_local().
#define DUNDI_MODEL_INBOUND (1 << 0) |
Definition at line 151 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 152 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 153 of file pbx_dundi.c.
Referenced by build_peer(), and model2str().
#define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME |
Definition at line 173 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 156 of file pbx_dundi.c.
Referenced by destroy_trans(), dundi_flush(), and dundi_show_peer().
#define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n" |
#define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
#define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n" |
#define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" |
#define FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n" |
#define FORMAT2 "%-12.12s %-12.12s %-10.10s\n" |
#define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
#define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" |
#define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" |
#define FORMAT2 "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n" |
#define MAX_OPTS 128 |
Definition at line 4196 of file pbx_dundi.c.
Referenced by build_mapping().
#define MAX_PACKET_SIZE 8192 |
Definition at line 147 of file pbx_dundi.c.
Referenced by handle_command_response(), and socket_read().
#define MAX_RESULTS 64 |
Definition at line 145 of file pbx_dundi.c.
#define MAX_WEIGHT 59999 |
Definition at line 149 of file pbx_dundi.c.
Referenced by build_mapping(), and get_mapping_weight().
anonymous enum |
FLAG_ISREG |
Transaction is register request |
FLAG_DEAD |
Transaction is dead |
FLAG_FINAL |
Transaction has final message sent |
FLAG_ISQUAL |
Transaction is a qualification |
FLAG_ENCRYPT |
Transaction is encrypted wiht ECX/DCX |
FLAG_SENDFULLKEY |
Send full key on transaction |
FLAG_STOREHIST |
Record historic performance |
Definition at line 158 of file pbx_dundi.c.
00158 { 00159 FLAG_ISREG = (1 << 0), /*!< Transaction is register request */ 00160 FLAG_DEAD = (1 << 1), /*!< Transaction is dead */ 00161 FLAG_FINAL = (1 << 2), /*!< Transaction has final message sent */ 00162 FLAG_ISQUAL = (1 << 3), /*!< Transaction is a qualification */ 00163 FLAG_ENCRYPT = (1 << 4), /*!< Transaction is encrypted wiht ECX/DCX */ 00164 FLAG_SENDFULLKEY = (1 << 5), /*!< Send full key on transaction */ 00165 FLAG_STOREHIST = (1 << 6), /*!< Record historic performance */ 00166 };
anonymous enum |
Definition at line 3882 of file pbx_dundi.c.
03882 { 03883 OPT_BYPASS_CACHE = (1 << 0), 03884 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 4867 of file pbx_dundi.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 4867 of file pbx_dundi.c.
static void abort_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3440 of file pbx_dundi.c.
References AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, destroy_trans(), and dundi_request::trans.
Referenced by dundi_lookup_internal().
03441 { 03442 struct dundi_transaction *trans; 03443 03444 AST_LIST_LOCK(&peers); 03445 while ((trans = AST_LIST_FIRST(&dr->trans))) { 03446 /* This will remove the transaction from the list */ 03447 destroy_trans(trans, 0); 03448 } 03449 AST_LIST_UNLOCK(&peers); 03450 }
static int ack_trans | ( | struct dundi_transaction * | trans, | |
int | iseqno | |||
) | [static] |
Definition at line 1989 of file pbx_dundi.c.
References AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), AST_SCHED_DEL, dundi_transaction::autokillid, destroy_packet(), destroy_packets(), dundi_packet::h, dundi_transaction::lasttrans, LOG_WARNING, dundi_hdr::oseqno, and dundi_transaction::packets.
Referenced by handle_frame().
01990 { 01991 struct dundi_packet *pack; 01992 01993 /* Ack transmitted packet corresponding to iseqno */ 01994 AST_LIST_TRAVERSE(&trans->packets, pack, list) { 01995 if ((pack->h->oseqno + 1) % 255 == iseqno) { 01996 destroy_packet(pack, 0); 01997 if (!AST_LIST_EMPTY(&trans->lasttrans)) { 01998 ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n"); 01999 destroy_packets(&trans->lasttrans); 02000 } 02001 AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list); 02002 AST_SCHED_DEL(sched, trans->autokillid); 02003 return 1; 02004 } 02005 } 02006 02007 return 0; 02008 }
static void append_permission | ( | struct permissionlist * | permlist, | |
const char * | s, | |||
int | allow | |||
) | [static] |
Definition at line 4183 of file pbx_dundi.c.
References permission::allow, ast_calloc, AST_LIST_INSERT_TAIL, and permission::name.
Referenced by build_peer().
04184 { 04185 struct permission *perm; 04186 04187 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1))) 04188 return; 04189 04190 strcpy(perm->name, s); 04191 perm->allow = allow; 04192 04193 AST_LIST_INSERT_TAIL(permlist, perm, list); 04194 }
static int append_transaction | ( | struct dundi_request * | dr, | |
struct dundi_peer * | p, | |||
int | ttl, | |||
dundi_eid * | avoid[] | |||
) | [static] |
Definition at line 3395 of file pbx_dundi.c.
References dundi_peer::addr, ast_debug, ast_eid_to_str(), AST_LIST_INSERT_HEAD, ast_strlen_zero(), create_transaction(), dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, dundi_peer::lastms, dundi_peer::maxms, dundi_request::number, dundi_transaction::parent, dundi_request::query_eid, dundi_request::trans, and dundi_transaction::ttl.
Referenced by build_transactions().
03396 { 03397 struct dundi_transaction *trans; 03398 int x; 03399 char eid_str[20]; 03400 char eid_str2[20]; 03401 03402 /* Ignore if not registered */ 03403 if (!p->addr.sin_addr.s_addr) 03404 return 0; 03405 if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms))) 03406 return 0; 03407 03408 if (ast_strlen_zero(dr->number)) 03409 ast_debug(1, "Will query peer '%s' for '%s' (context '%s')\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext); 03410 else 03411 ast_debug(1, "Will query peer '%s' for '%s@%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext); 03412 03413 trans = create_transaction(p); 03414 if (!trans) 03415 return -1; 03416 trans->parent = dr; 03417 trans->ttl = ttl; 03418 for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++) 03419 trans->eids[x] = *avoid[x]; 03420 trans->eidcount = x; 03421 AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist); 03422 03423 return 0; 03424 }
static void apply_peer | ( | struct dundi_transaction * | trans, | |
struct dundi_peer * | p | |||
) | [static] |
Definition at line 1276 of file pbx_dundi.c.
References dundi_peer::addr, dundi_transaction::addr, ast_set_flag, ast_strlen_zero(), dundi_transaction::autokilltimeout, DUNDI_DEFAULT_RETRANS_TIMER, dundi_peer::eid, FLAG_ENCRYPT, dundi_peer::inkey, dundi_peer::lastms, dundi_peer::maxms, dundi_transaction::retranstimer, dundi_transaction::them_eid, dundi_peer::us_eid, and dundi_transaction::us_eid.
Referenced by create_transaction(), and handle_command_response().
01277 { 01278 if (!trans->addr.sin_addr.s_addr) 01279 memcpy(&trans->addr, &p->addr, sizeof(trans->addr)); 01280 trans->us_eid = p->us_eid; 01281 trans->them_eid = p->eid; 01282 /* Enable encryption if appropriate */ 01283 if (!ast_strlen_zero(p->inkey)) 01284 ast_set_flag(trans, FLAG_ENCRYPT); 01285 if (p->maxms) { 01286 trans->autokilltimeout = p->maxms; 01287 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 01288 if (p->lastms > 1) { 01289 trans->retranstimer = p->lastms * 2; 01290 /* Keep it from being silly */ 01291 if (trans->retranstimer < 150) 01292 trans->retranstimer = 150; 01293 } 01294 if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER) 01295 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 01296 } else 01297 trans->autokilltimeout = global_autokilltimeout; 01298 }
static unsigned long avoid_crc32 | ( | dundi_eid * | avoid[] | ) | [static] |
Definition at line 3561 of file pbx_dundi.c.
References dundi_request::crc32.
Referenced by dundi_lookup_internal().
03562 { 03563 /* Idea is that we're calculating a checksum which is independent of 03564 the order that the EID's are listed in */ 03565 uint32_t acrc32 = 0; 03566 int x; 03567 for (x=0;avoid[x];x++) { 03568 /* Order doesn't matter */ 03569 if (avoid[x+1]) { 03570 acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid)); 03571 } 03572 } 03573 return acrc32; 03574 }
static void build_iv | ( | unsigned char * | iv | ) | [static] |
Definition at line 522 of file pbx_dundi.c.
References ast_random().
Referenced by build_secret(), dundi_encrypt(), and update_key().
00523 { 00524 /* XXX Would be nice to be more random XXX */ 00525 unsigned int *fluffy; 00526 int x; 00527 fluffy = (unsigned int *)(iv); 00528 for (x=0;x<4;x++) 00529 fluffy[x] = ast_random(); 00530 }
static void build_mapping | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 4198 of file pbx_dundi.c.
References dundi_mapping::_weight, ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strdup, 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, MAX_WEIGHT, dundi_mapping::options, str2tech(), dundi_mapping::tech, and dundi_mapping::weightstr.
Referenced by set_config().
04199 { 04200 char *t, *fields[MAX_OPTS]; 04201 struct dundi_mapping *map; 04202 int x; 04203 int y; 04204 04205 t = ast_strdupa(value); 04206 04207 AST_LIST_TRAVERSE(&mappings, map, list) { 04208 /* Find a double match */ 04209 if (!strcasecmp(map->dcontext, name) && 04210 (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 04211 (!value[strlen(map->lcontext)] || 04212 (value[strlen(map->lcontext)] == ',')))) 04213 break; 04214 } 04215 if (!map) { 04216 if (!(map = ast_calloc(1, sizeof(*map)))) 04217 return; 04218 AST_LIST_INSERT_HEAD(&mappings, map, list); 04219 map->dead = 1; 04220 } 04221 map->options = 0; 04222 memset(fields, 0, sizeof(fields)); 04223 x = 0; 04224 while (t && x < MAX_OPTS) { 04225 fields[x++] = t; 04226 t = strchr(t, ','); 04227 if (t) { 04228 *t = '\0'; 04229 t++; 04230 } 04231 } /* Russell was here, arrrr! */ 04232 if ((x == 1) && ast_strlen_zero(fields[0])) { 04233 /* Placeholder mapping */ 04234 ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); 04235 map->dead = 0; 04236 } else if (x >= 4) { 04237 ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); 04238 ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext)); 04239 if ((sscanf(fields[1], "%30d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) { 04240 ast_copy_string(map->dest, fields[3], sizeof(map->dest)); 04241 if ((map->tech = str2tech(fields[2]))) 04242 map->dead = 0; 04243 } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') { 04244 map->weightstr = ast_strdup(fields[1]); 04245 ast_copy_string(map->dest, fields[3], sizeof(map->dest)); 04246 if ((map->tech = str2tech(fields[2]))) 04247 map->dead = 0; 04248 } else { 04249 ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext); 04250 } 04251 for (y = 4;y < x; y++) { 04252 if (!strcasecmp(fields[y], "nounsolicited")) 04253 map->options |= DUNDI_FLAG_NOUNSOLICITED; 04254 else if (!strcasecmp(fields[y], "nocomunsolicit")) 04255 map->options |= DUNDI_FLAG_NOCOMUNSOLICIT; 04256 else if (!strcasecmp(fields[y], "residential")) 04257 map->options |= DUNDI_FLAG_RESIDENTIAL; 04258 else if (!strcasecmp(fields[y], "commercial")) 04259 map->options |= DUNDI_FLAG_COMMERCIAL; 04260 else if (!strcasecmp(fields[y], "mobile")) 04261 map->options |= DUNDI_FLAG_MOBILE; 04262 else if (!strcasecmp(fields[y], "nopartial")) 04263 map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL; 04264 else 04265 ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]); 04266 } 04267 } else 04268 ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x); 04269 }
static void build_peer | ( | dundi_eid * | eid, | |
struct ast_variable * | v, | |||
int * | globalpcmode | |||
) | [static] |
Definition at line 4353 of file pbx_dundi.c.
References dundi_peer::addr, append_permission(), ast_calloc, ast_copy_string(), ast_eid_cmp(), ast_eid_to_str(), 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_str_to_eid(), ast_true(), dundi_peer::dead, DEFAULT_MAXMS, destroy_permissions(), do_register(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_MODEL_SYMMETRIC, DUNDI_PORT, dundi_peer::dynamic, dundi_peer::eid, hp, dundi_peer::include, dundi_peer::inkey, ast_variable::lineno, LOG_WARNING, dundi_peer::maxms, dundi_peer::model, ast_variable::name, ast_variable::next, dundi_peer::order, dundi_peer::outkey, dundi_peer::pcmodel, dundi_peer::permit, populate_addr(), qualify_peer(), dundi_peer::qualifyid, dundi_peer::registerexpire, dundi_peer::registerid, dundi_peer::us_eid, and ast_variable::value.
Referenced by set_config().
04354 { 04355 struct dundi_peer *peer; 04356 struct ast_hostent he; 04357 struct hostent *hp; 04358 dundi_eid testeid; 04359 int needregister=0; 04360 char eid_str[20]; 04361 04362 AST_LIST_LOCK(&peers); 04363 AST_LIST_TRAVERSE(&peers, peer, list) { 04364 if (!ast_eid_cmp(&peer->eid, eid)) { 04365 break; 04366 } 04367 } 04368 if (!peer) { 04369 /* Add us into the list */ 04370 if (!(peer = ast_calloc(1, sizeof(*peer)))) { 04371 AST_LIST_UNLOCK(&peers); 04372 return; 04373 } 04374 peer->registerid = -1; 04375 peer->registerexpire = -1; 04376 peer->qualifyid = -1; 04377 peer->addr.sin_family = AF_INET; 04378 peer->addr.sin_port = htons(DUNDI_PORT); 04379 populate_addr(peer, eid); 04380 AST_LIST_INSERT_HEAD(&peers, peer, list); 04381 } 04382 peer->dead = 0; 04383 peer->eid = *eid; 04384 peer->us_eid = global_eid; 04385 destroy_permissions(&peer->permit); 04386 destroy_permissions(&peer->include); 04387 AST_SCHED_DEL(sched, peer->registerid); 04388 for (; v; v = v->next) { 04389 if (!strcasecmp(v->name, "inkey")) { 04390 ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey)); 04391 } else if (!strcasecmp(v->name, "outkey")) { 04392 ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey)); 04393 } else if (!strcasecmp(v->name, "port")) { 04394 peer->addr.sin_port = htons(atoi(v->value)); 04395 } else if (!strcasecmp(v->name, "host")) { 04396 if (!strcasecmp(v->value, "dynamic")) { 04397 peer->dynamic = 1; 04398 } else { 04399 hp = ast_gethostbyname(v->value, &he); 04400 if (hp) { 04401 memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); 04402 peer->dynamic = 0; 04403 } else { 04404 ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); 04405 peer->dead = 1; 04406 } 04407 } 04408 } else if (!strcasecmp(v->name, "ustothem")) { 04409 if (!ast_str_to_eid(&testeid, v->value)) 04410 peer->us_eid = testeid; 04411 else 04412 ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno); 04413 } else if (!strcasecmp(v->name, "include")) { 04414 append_permission(&peer->include, v->value, 1); 04415 } else if (!strcasecmp(v->name, "permit")) { 04416 append_permission(&peer->permit, v->value, 1); 04417 } else if (!strcasecmp(v->name, "noinclude")) { 04418 append_permission(&peer->include, v->value, 0); 04419 } else if (!strcasecmp(v->name, "deny")) { 04420 append_permission(&peer->permit, v->value, 0); 04421 } else if (!strcasecmp(v->name, "register")) { 04422 needregister = ast_true(v->value); 04423 } else if (!strcasecmp(v->name, "order")) { 04424 if (!strcasecmp(v->value, "primary")) 04425 peer->order = 0; 04426 else if (!strcasecmp(v->value, "secondary")) 04427 peer->order = 1; 04428 else if (!strcasecmp(v->value, "tertiary")) 04429 peer->order = 2; 04430 else if (!strcasecmp(v->value, "quartiary")) 04431 peer->order = 3; 04432 else { 04433 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); 04434 } 04435 } else if (!strcasecmp(v->name, "qualify")) { 04436 if (!strcasecmp(v->value, "no")) { 04437 peer->maxms = 0; 04438 } else if (!strcasecmp(v->value, "yes")) { 04439 peer->maxms = DEFAULT_MAXMS; 04440 } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) { 04441 ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 04442 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno); 04443 peer->maxms = 0; 04444 } 04445 } else if (!strcasecmp(v->name, "model")) { 04446 if (!strcasecmp(v->value, "inbound")) 04447 peer->model = DUNDI_MODEL_INBOUND; 04448 else if (!strcasecmp(v->value, "outbound")) 04449 peer->model = DUNDI_MODEL_OUTBOUND; 04450 else if (!strcasecmp(v->value, "symmetric")) 04451 peer->model = DUNDI_MODEL_SYMMETRIC; 04452 else if (!strcasecmp(v->value, "none")) 04453 peer->model = 0; 04454 else { 04455 ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 04456 v->value, v->lineno); 04457 } 04458 } else if (!strcasecmp(v->name, "precache")) { 04459 if (!strcasecmp(v->value, "inbound")) 04460 peer->pcmodel = DUNDI_MODEL_INBOUND; 04461 else if (!strcasecmp(v->value, "outbound")) 04462 peer->pcmodel = DUNDI_MODEL_OUTBOUND; 04463 else if (!strcasecmp(v->value, "symmetric")) 04464 peer->pcmodel = DUNDI_MODEL_SYMMETRIC; 04465 else if (!strcasecmp(v->value, "none")) 04466 peer->pcmodel = 0; 04467 else { 04468 ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 04469 v->value, v->lineno); 04470 } 04471 } 04472 } 04473 (*globalpcmode) |= peer->pcmodel; 04474 if (!peer->model && !peer->pcmodel) { 04475 ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 04476 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04477 peer->dead = 1; 04478 } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { 04479 ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 04480 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04481 peer->dead = 1; 04482 } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) { 04483 ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 04484 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04485 peer->dead = 1; 04486 } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) { 04487 ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 04488 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04489 } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { 04490 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", 04491 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04492 } else { 04493 if (needregister) { 04494 peer->registerid = ast_sched_add(sched, 2000, do_register, peer); 04495 } 04496 if (ast_eid_cmp(&peer->eid, &empty_eid)) { 04497 qualify_peer(peer, 1); 04498 } 04499 } 04500 AST_LIST_UNLOCK(&peers); 04501 }
static void build_secret | ( | char * | secret, | |
int | seclen | |||
) | [static] |
Definition at line 2079 of file pbx_dundi.c.
References ast_base64encode(), and build_iv().
Referenced by check_password(), and load_password().
02080 { 02081 unsigned char tmp[16]; 02082 char *s; 02083 build_iv(tmp); 02084 secret[0] = '\0'; 02085 ast_base64encode(secret, tmp, sizeof(tmp), seclen); 02086 /* Eliminate potential bad characters */ 02087 while((s = strchr(secret, ';'))) *s = '+'; 02088 while((s = strchr(secret, '/'))) *s = '+'; 02089 while((s = strchr(secret, ':'))) *s = '+'; 02090 while((s = strchr(secret, '@'))) *s = '+'; 02091 }
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 3452 of file pbx_dundi.c.
References append_transaction(), ast_clear_flag_nonstd, ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, cache_lookup(), dundi_request::crc32, dundi_request::dcontext, dundi_eid_zero(), DUNDI_HINT_UNAFFECTED, DUNDI_MODEL_OUTBOUND, dundi_peer::eid, dundi_request::expiration, has_permission(), dundi_request::hmd, dundi_peer::include, dundi_peer::model, dundi_peer::order, pass, dundi_peer::pcmodel, dundi_peer::permit, and dundi_peer::us_eid.
Referenced by dundi_lookup_internal(), dundi_precache_internal(), and dundi_query_eid_internal().
03453 { 03454 struct dundi_peer *p; 03455 int x; 03456 int res; 03457 int pass; 03458 int allowconnect; 03459 char eid_str[20]; 03460 AST_LIST_LOCK(&peers); 03461 AST_LIST_TRAVERSE(&peers, p, list) { 03462 if (modeselect == 1) { 03463 /* Send the precache to push upstreams only! */ 03464 pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND); 03465 allowconnect = 1; 03466 } else { 03467 /* Normal lookup / EID query */ 03468 pass = has_permission(&p->include, dr->dcontext); 03469 allowconnect = p->model & DUNDI_MODEL_OUTBOUND; 03470 } 03471 if (skip) { 03472 if (!ast_eid_cmp(skip, &p->eid)) 03473 pass = 0; 03474 } 03475 if (pass) { 03476 if (p->order <= order) { 03477 /* Check order first, then check cache, regardless of 03478 omissions, this gets us more likely to not have an 03479 affected answer. */ 03480 if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) { 03481 res = 0; 03482 /* Make sure we haven't already seen it and that it won't 03483 affect our answer */ 03484 for (x=0;avoid[x];x++) { 03485 if (!ast_eid_cmp(avoid[x], &p->eid) || !ast_eid_cmp(avoid[x], &p->us_eid)) { 03486 /* If not a direct connection, it affects our answer */ 03487 if (directs && !directs[x]) 03488 ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED); 03489 break; 03490 } 03491 } 03492 /* Make sure we can ask */ 03493 if (allowconnect) { 03494 if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) { 03495 /* Check for a matching or 0 cache entry */ 03496 append_transaction(dr, p, ttl, avoid); 03497 } else { 03498 ast_debug(1, "Avoiding '%s' in transaction\n", ast_eid_to_str(eid_str, sizeof(eid_str), avoid[x])); 03499 } 03500 } 03501 } 03502 *foundcache |= res; 03503 } else if (!*skipped || (p->order < *skipped)) 03504 *skipped = p->order; 03505 } 03506 } 03507 AST_LIST_UNLOCK(&peers); 03508 }
static int cache_lookup | ( | struct dundi_request * | req, | |
dundi_eid * | peer_eid, | |||
uint32_t | crc32, | |||
int * | lowexpiration | |||
) | [static] |
Definition at line 1224 of file pbx_dundi.c.
References ast_copy_string(), ast_eid_to_str(), cache_lookup_internal(), dundi_request::dcontext, 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().
01225 { 01226 char key[256]; 01227 char eid_str[20]; 01228 char eidroot_str[20]; 01229 time_t now; 01230 int res=0; 01231 int res2=0; 01232 char eid_str_full[20]; 01233 char tmp[256]=""; 01234 int x; 01235 01236 time(&now); 01237 dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid); 01238 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 01239 ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid); 01240 snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32); 01241 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01242 snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, (unsigned)0); 01243 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01244 snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str); 01245 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01246 x = 0; 01247 if (!req->respcount) { 01248 while(!res2) { 01249 /* Look and see if we have a hint that would preclude us from looking at this 01250 peer for this number. */ 01251 if (!(tmp[x] = req->number[x])) 01252 break; 01253 x++; 01254 /* Check for hints */ 01255 snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32); 01256 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01257 snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, (unsigned)0); 01258 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01259 snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str); 01260 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01261 if (res2) { 01262 if (strlen(tmp) > strlen(req->hmd->exten)) { 01263 /* Update meta data if appropriate */ 01264 ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten)); 01265 } 01266 } 01267 } 01268 res |= res2; 01269 } 01270 01271 return res; 01272 }
static int cache_lookup_internal | ( | time_t | now, | |
struct dundi_request * | req, | |||
char * | key, | |||
char * | eid_str_full, | |||
int * | lowexpiration | |||
) | [static] |
Definition at line 1152 of file pbx_dundi.c.
References ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_db_del(), ast_db_get(), ast_debug, ast_eid_to_str(), AST_FLAGS_ALL, ast_get_time_t(), dundi_result::dest, dundi_request::dr, 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, dundi_request::respcount, dundi_result::tech, tech2str(), dundi_result::techint, and dundi_result::weight.
Referenced by cache_lookup().
01153 { 01154 char data[1024]; 01155 char *ptr, *term, *src; 01156 int tech; 01157 struct ast_flags flags; 01158 int weight; 01159 int length; 01160 int z; 01161 char fs[256]; 01162 01163 /* Build request string */ 01164 if (!ast_db_get("dundi/cache", key, data, sizeof(data))) { 01165 time_t timeout; 01166 ptr = data; 01167 if (!ast_get_time_t(ptr, &timeout, 0, &length)) { 01168 int expiration = timeout - now; 01169 if (expiration > 0) { 01170 ast_debug(1, "Found cache expiring in %d seconds!\n", expiration); 01171 ptr += length + 1; 01172 while((sscanf(ptr, "%30d/%30d/%30d/%n", (int *)&(flags.flags), &weight, &tech, &length) == 3)) { 01173 ptr += length; 01174 term = strchr(ptr, '|'); 01175 if (term) { 01176 *term = '\0'; 01177 src = strrchr(ptr, '/'); 01178 if (src) { 01179 *src = '\0'; 01180 src++; 01181 } else 01182 src = ""; 01183 ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", 01184 tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full); 01185 /* Make sure it's not already there */ 01186 for (z=0;z<req->respcount;z++) { 01187 if ((req->dr[z].techint == tech) && 01188 !strcmp(req->dr[z].dest, ptr)) 01189 break; 01190 } 01191 if (z == req->respcount) { 01192 /* Copy into parent responses */ 01193 ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL); 01194 req->dr[req->respcount].weight = weight; 01195 req->dr[req->respcount].techint = tech; 01196 req->dr[req->respcount].expiration = expiration; 01197 dundi_str_short_to_eid(&req->dr[req->respcount].eid, src); 01198 ast_eid_to_str(req->dr[req->respcount].eid_str, 01199 sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid); 01200 ast_copy_string(req->dr[req->respcount].dest, ptr, 01201 sizeof(req->dr[req->respcount].dest)); 01202 ast_copy_string(req->dr[req->respcount].tech, tech2str(tech), 01203 sizeof(req->dr[req->respcount].tech)); 01204 req->respcount++; 01205 ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK); 01206 } else if (req->dr[z].weight > weight) 01207 req->dr[z].weight = weight; 01208 ptr = term + 1; 01209 } 01210 } 01211 /* We found *something* cached */ 01212 if (expiration < *lowexpiration) 01213 *lowexpiration = expiration; 01214 return 1; 01215 } else 01216 ast_db_del("dundi/cache", key); 01217 } else 01218 ast_db_del("dundi/cache", key); 01219 } 01220 01221 return 0; 01222 }
static int cache_save | ( | dundi_eid * | eidpeer, | |
struct dundi_request * | req, | |||
int | start, | |||
int | unaffected, | |||
int | expiration, | |||
int | push | |||
) | [static] |
Definition at line 881 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().
00882 { 00883 int x; 00884 char key1[256]; 00885 char key2[256]; 00886 char data[1024]; 00887 char eidpeer_str[20]; 00888 char eidroot_str[20]; 00889 time_t timeout; 00890 00891 if (expiration < 1) 00892 expiration = dundi_cache_time; 00893 00894 /* Keep pushes a little longer, cut pulls a little short */ 00895 if (push) 00896 expiration += 10; 00897 else 00898 expiration -= 10; 00899 if (expiration < 1) 00900 expiration = 1; 00901 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); 00902 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 00903 snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32); 00904 snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str); 00905 /* Build request string */ 00906 time(&timeout); 00907 timeout += expiration; 00908 snprintf(data, sizeof(data), "%ld|", (long)(timeout)); 00909 for (x=start;x<req->respcount;x++) { 00910 /* Skip anything with an illegal pipe in it */ 00911 if (strchr(req->dr[x].dest, '|')) 00912 continue; 00913 snprintf(data + strlen(data), sizeof(data) - strlen(data), "%u/%d/%d/%s/%s|", 00914 req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 00915 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid)); 00916 } 00917 ast_db_put("dundi/cache", key1, data); 00918 ast_db_put("dundi/cache", key2, data); 00919 return 0; 00920 }
static int cache_save_hint | ( | dundi_eid * | eidpeer, | |
struct dundi_request * | req, | |||
struct dundi_hint * | hint, | |||
int | expiration | |||
) | [static] |
Definition at line 846 of file pbx_dundi.c.
References ast_db_put(), ast_debug, 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, and dundi_request::root_eid.
Referenced by dundi_prop_precache(), and handle_command_response().
00847 { 00848 int unaffected; 00849 char key1[256]; 00850 char key2[256]; 00851 char eidpeer_str[20]; 00852 char eidroot_str[20]; 00853 char data[80]; 00854 time_t timeout; 00855 00856 if (expiration < 0) 00857 expiration = dundi_cache_time; 00858 00859 /* Only cache hint if "don't ask" is there... */ 00860 if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK))) 00861 return 0; 00862 00863 unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED)); 00864 00865 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); 00866 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 00867 snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32); 00868 snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str); 00869 00870 time(&timeout); 00871 timeout += expiration; 00872 snprintf(data, sizeof(data), "%ld|", (long)(timeout)); 00873 00874 ast_db_put("dundi/cache", key1, data); 00875 ast_debug(1, "Caching hint at '%s'\n", key1); 00876 ast_db_put("dundi/cache", key2, data); 00877 ast_debug(1, "Caching hint at '%s'\n", key2); 00878 return 0; 00879 }
static void cancel_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3426 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, DUNDI_COMMAND_CANCEL, dundi_send(), dundi_transaction::parent, and dundi_request::trans.
Referenced by dundi_lookup_internal(), and dundi_precache_internal().
03427 { 03428 struct dundi_transaction *trans; 03429 03430 AST_LIST_LOCK(&peers); 03431 while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) { 03432 /* Orphan transaction from request */ 03433 trans->parent = NULL; 03434 /* Send final cancel */ 03435 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 03436 } 03437 AST_LIST_UNLOCK(&peers); 03438 }
static int check_key | ( | struct dundi_peer * | peer, | |
unsigned char * | newkey, | |||
unsigned char * | newsig, | |||
uint32_t | keycrc32 | |||
) | [static] |
Definition at line 1470 of file pbx_dundi.c.
References ast_aes_set_decrypt_key(), ast_aes_set_encrypt_key(), ast_check_signature_bin(), ast_debug, ast_decrypt_bin(), ast_eid_to_str(), ast_key_get(), AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), dundi_peer::eid, dundi_peer::inkey, LOG_NOTICE, dundi_peer::outkey, dundi_peer::rxenckey, dundi_peer::them_dcx, dundi_peer::them_ecx, and dundi_peer::them_keycrc32.
Referenced by handle_command_response().
01471 { 01472 unsigned char dst[128]; 01473 int res; 01474 struct ast_key *key, *skey; 01475 char eid_str[20]; 01476 ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32); 01477 if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) { 01478 /* A match */ 01479 return 1; 01480 } else if (!newkey || !newsig) 01481 return 0; 01482 if (!memcmp(peer->rxenckey, newkey, 128) && 01483 !memcmp(peer->rxenckey + 128, newsig, 128)) { 01484 /* By definition, a match */ 01485 return 1; 01486 } 01487 /* Decrypt key */ 01488 key = ast_key_get(peer->outkey, AST_KEY_PRIVATE); 01489 if (!key) { 01490 ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n", 01491 peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01492 return -1; 01493 } 01494 01495 skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC); 01496 if (!skey) { 01497 ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n", 01498 peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01499 return -1; 01500 } 01501 01502 /* First check signature */ 01503 res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig); 01504 if (res) 01505 return 0; 01506 01507 res = ast_decrypt_bin(dst, newkey, sizeof(dst), key); 01508 if (res != 16) { 01509 if (res >= 0) 01510 ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res); 01511 return 0; 01512 } 01513 /* Decrypted, passes signature */ 01514 ast_debug(1, "Wow, new key combo passed signature and decrypt!\n"); 01515 memcpy(peer->rxenckey, newkey, 128); 01516 memcpy(peer->rxenckey + 128, newsig, 128); 01517 peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128); 01518 ast_aes_set_decrypt_key(dst, &peer->them_dcx); 01519 ast_aes_set_encrypt_key(dst, &peer->them_ecx); 01520 return 1; 01521 }
static void check_password | ( | void | ) | [static] |
Definition at line 2146 of file pbx_dundi.c.
References ast_copy_string(), build_secret(), and save_secret().
Referenced by network_thread().
02147 { 02148 char oldsecret[80]; 02149 time_t now; 02150 02151 time(&now); 02152 #if 0 02153 printf("%ld/%ld\n", now, rotatetime); 02154 #endif 02155 if ((now - rotatetime) >= 0) { 02156 /* Time to rotate keys */ 02157 ast_copy_string(oldsecret, cursecret, sizeof(oldsecret)); 02158 build_secret(cursecret, sizeof(cursecret)); 02159 save_secret(cursecret, oldsecret); 02160 } 02161 }
static int check_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3547 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.
Referenced by dundi_lookup_internal().
03548 { 03549 struct dundi_request *cur; 03550 03551 AST_LIST_LOCK(&peers); 03552 AST_LIST_TRAVERSE(&requests, cur, list) { 03553 if (cur == dr) 03554 break; 03555 } 03556 AST_LIST_UNLOCK(&peers); 03557 03558 return cur ? 1 : 0; 03559 }
static char* complete_peer_helper | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state, | |||
int | rpos | |||
) | [static] |
Definition at line 2381 of file pbx_dundi.c.
References ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, dundi_peer::eid, and len().
Referenced by dundi_show_peer().
02382 { 02383 int which=0, len; 02384 char *ret = NULL; 02385 struct dundi_peer *p; 02386 char eid_str[20]; 02387 02388 if (pos != rpos) 02389 return NULL; 02390 AST_LIST_LOCK(&peers); 02391 len = strlen(word); 02392 AST_LIST_TRAVERSE(&peers, p, list) { 02393 const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid); 02394 if (!strncasecmp(word, s, len) && ++which > state) { 02395 ret = ast_strdup(s); 02396 break; 02397 } 02398 } 02399 AST_LIST_UNLOCK(&peers); 02400 return ret; 02401 }
static struct dundi_transaction * create_transaction | ( | struct dundi_peer * | p | ) | [static, read] |
Definition at line 2900 of file pbx_dundi.c.
References dundi_peer::addr, apply_peer(), ast_calloc, AST_LIST_INSERT_HEAD, ast_set_flag, ast_tvnow(), dundi_transaction::autokillid, DUNDI_DEFAULT_RETRANS_TIMER, FLAG_SENDFULLKEY, FLAG_STOREHIST, get_trans_id(), dundi_transaction::retranstimer, dundi_peer::sentfullkey, dundi_transaction::start, and dundi_transaction::strans.
Referenced by append_transaction(), do_register(), find_transaction(), and qualify_peer().
02901 { 02902 struct dundi_transaction *trans; 02903 int tid; 02904 02905 /* Don't allow creation of transactions to non-registered peers */ 02906 if (p && !p->addr.sin_addr.s_addr) 02907 return NULL; 02908 tid = get_trans_id(); 02909 if (tid < 1) 02910 return NULL; 02911 if (!(trans = ast_calloc(1, sizeof(*trans)))) 02912 return NULL; 02913 02914 if (global_storehistory) { 02915 trans->start = ast_tvnow(); 02916 ast_set_flag(trans, FLAG_STOREHIST); 02917 } 02918 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 02919 trans->autokillid = -1; 02920 if (p) { 02921 apply_peer(trans, p); 02922 if (!p->sentfullkey) 02923 ast_set_flag(trans, FLAG_SENDFULLKEY); 02924 } 02925 trans->strans = tid; 02926 AST_LIST_INSERT_HEAD(&alltrans, trans, all); 02927 02928 return trans; 02929 }
static int decrypt_memcpy | ( | unsigned char * | dst, | |
unsigned char * | src, | |||
int | len, | |||
unsigned char * | iv, | |||
ast_aes_decrypt_key * | dcx | |||
) | [static] |
Definition at line 1367 of file pbx_dundi.c.
References ast_aes_decrypt().
Referenced by dundi_decrypt().
01368 { 01369 unsigned char lastblock[16]; 01370 int x; 01371 memcpy(lastblock, iv, sizeof(lastblock)); 01372 while(len > 0) { 01373 ast_aes_decrypt(src, dst, dcx); 01374 for (x=0;x<16;x++) 01375 dst[x] ^= lastblock[x]; 01376 memcpy(lastblock, src, sizeof(lastblock)); 01377 dst += 16; 01378 src += 16; 01379 len -= 16; 01380 } 01381 return 0; 01382 }
static void deep_copy_peer | ( | struct dundi_peer * | peer_dst, | |
const struct dundi_peer * | peer_src | |||
) | [static] |
Definition at line 1523 of file pbx_dundi.c.
References permission::allow, ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, dundi_peer::include, permission::name, and dundi_peer::permit.
Referenced by handle_command_response().
01524 { 01525 struct permission *cur, *perm; 01526 01527 memcpy(peer_dst, peer_src, sizeof(*peer_dst)); 01528 01529 memset(&peer_dst->permit, 0, sizeof(peer_dst->permit)); 01530 memset(&peer_dst->include, 0, sizeof(peer_dst->permit)); 01531 01532 AST_LIST_TRAVERSE(&peer_src->permit, cur, list) { 01533 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1))) 01534 continue; 01535 01536 perm->allow = cur->allow; 01537 strcpy(perm->name, cur->name); 01538 01539 AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list); 01540 } 01541 01542 AST_LIST_TRAVERSE(&peer_src->include, cur, list) { 01543 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1))) 01544 continue; 01545 01546 perm->allow = cur->allow; 01547 strcpy(perm->name, cur->name); 01548 01549 AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list); 01550 } 01551 }
static void destroy_map | ( | struct dundi_mapping * | map | ) | [static] |
Definition at line 4146 of file pbx_dundi.c.
References ast_free, and dundi_mapping::weightstr.
Referenced by prune_mappings().
static void destroy_packet | ( | struct dundi_packet * | pack, | |
int | needfree | |||
) | [static] |
Definition at line 2947 of file pbx_dundi.c.
References ast_free, AST_LIST_REMOVE, AST_SCHED_DEL, dundi_transaction::packets, dundi_packet::parent, and dundi_packet::retransid.
Referenced by ack_trans().
02948 { 02949 if (pack->parent) 02950 AST_LIST_REMOVE(&pack->parent->packets, pack, list); 02951 AST_SCHED_DEL(sched, pack->retransid); 02952 if (needfree) 02953 ast_free(pack); 02954 }
static void destroy_packets | ( | struct packetlist * | p | ) | [static] |
Definition at line 1978 of file pbx_dundi.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_SCHED_DEL, and dundi_packet::retransid.
Referenced by ack_trans(), destroy_trans(), and handle_frame().
01979 { 01980 struct dundi_packet *pack; 01981 01982 while ((pack = AST_LIST_REMOVE_HEAD(p, list))) { 01983 AST_SCHED_DEL(sched, pack->retransid); 01984 ast_free(pack); 01985 } 01986 }
static void destroy_peer | ( | struct dundi_peer * | peer | ) | [static] |
Definition at line 4135 of file pbx_dundi.c.
References ast_free, AST_SCHED_DEL, destroy_permissions(), destroy_trans(), dundi_peer::include, dundi_peer::permit, dundi_peer::qualifyid, dundi_peer::registerid, and dundi_peer::regtrans.
Referenced by prune_peers().
04136 { 04137 AST_SCHED_DEL(sched, peer->registerid); 04138 if (peer->regtrans) 04139 destroy_trans(peer->regtrans, 0); 04140 AST_SCHED_DEL(sched, peer->qualifyid); 04141 destroy_permissions(&peer->permit); 04142 destroy_permissions(&peer->include); 04143 ast_free(peer); 04144 }
static void destroy_permissions | ( | struct permissionlist * | permlist | ) | [static] |
Definition at line 4127 of file pbx_dundi.c.
References ast_free, and AST_LIST_REMOVE_HEAD.
Referenced by build_peer(), and destroy_peer().
04128 { 04129 struct permission *perm; 04130 04131 while ((perm = AST_LIST_REMOVE_HEAD(permlist, list))) 04132 ast_free(perm); 04133 }
static void destroy_trans | ( | struct dundi_transaction * | trans, | |
int | fromtimeout | |||
) | [static] |
Definition at line 2956 of file pbx_dundi.c.
References ast_eid_cmp(), ast_eid_to_str(), ast_free, 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, ast_tvdiff_ms(), ast_tvnow(), dundi_transaction::autokillid, dundi_peer::avgms, dundi_request::dcontext, destroy_packets(), DUNDI_TIMING_HISTORY, dundi_peer::eid, errno, FLAG_DEAD, FLAG_ISQUAL, FLAG_ISREG, FLAG_STOREHIST, dundi_peer::lastms, dundi_transaction::lasttrans, LOG_NOTICE, LOG_WARNING, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::maxms, dundi_request::number, dundi_transaction::packets, dundi_transaction::parent, dundi_request::pfds, dundi_peer::qualtrans, dundi_peer::qualtx, dundi_peer::regtrans, dundi_transaction::start, dundi_transaction::them_eid, dundi_transaction::thread, and dundi_request::trans.
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().
02957 { 02958 struct dundi_peer *peer; 02959 int ms; 02960 int x; 02961 int cnt; 02962 char eid_str[20]; 02963 if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) { 02964 AST_LIST_TRAVERSE(&peers, peer, list) { 02965 if (peer->regtrans == trans) 02966 peer->regtrans = NULL; 02967 if (peer->qualtrans == trans) { 02968 if (fromtimeout) { 02969 if (peer->lastms > -1) 02970 ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02971 peer->lastms = -1; 02972 } else { 02973 ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx); 02974 if (ms < 1) 02975 ms = 1; 02976 if (ms < peer->maxms) { 02977 if ((peer->lastms >= peer->maxms) || (peer->lastms < 0)) 02978 ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02979 } else if (peer->lastms < peer->maxms) { 02980 ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms); 02981 } 02982 peer->lastms = ms; 02983 } 02984 peer->qualtrans = NULL; 02985 } 02986 if (ast_test_flag(trans, FLAG_STOREHIST)) { 02987 if (trans->parent && !ast_strlen_zero(trans->parent->number)) { 02988 if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) { 02989 peer->avgms = 0; 02990 cnt = 0; 02991 if (peer->lookups[DUNDI_TIMING_HISTORY-1]) 02992 ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]); 02993 for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) { 02994 peer->lookuptimes[x] = peer->lookuptimes[x-1]; 02995 peer->lookups[x] = peer->lookups[x-1]; 02996 if (peer->lookups[x]) { 02997 peer->avgms += peer->lookuptimes[x]; 02998 cnt++; 02999 } 03000 } 03001 peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start); 03002 peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2); 03003 if (peer->lookups[0]) { 03004 sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext); 03005 peer->avgms += peer->lookuptimes[0]; 03006 cnt++; 03007 } 03008 if (cnt) 03009 peer->avgms /= cnt; 03010 } 03011 } 03012 } 03013 } 03014 } 03015 if (trans->parent) { 03016 /* Unlink from parent if appropriate */ 03017 AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist); 03018 if (AST_LIST_EMPTY(&trans->parent->trans)) { 03019 /* Wake up sleeper */ 03020 if (trans->parent->pfds[1] > -1) { 03021 if (write(trans->parent->pfds[1], "killa!", 6) < 0) { 03022 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 03023 } 03024 } 03025 } 03026 } 03027 /* Unlink from all trans */ 03028 AST_LIST_REMOVE(&alltrans, trans, all); 03029 destroy_packets(&trans->packets); 03030 destroy_packets(&trans->lasttrans); 03031 AST_SCHED_DEL(sched, trans->autokillid); 03032 if (trans->thread) { 03033 /* If used by a thread, mark as dead and be done */ 03034 ast_set_flag(trans, FLAG_DEAD); 03035 } else 03036 ast_free(trans); 03037 }
static int discover_transactions | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3278 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_discover(), and dundi_request::trans.
Referenced by dundi_lookup_internal().
03279 { 03280 struct dundi_transaction *trans; 03281 AST_LIST_LOCK(&peers); 03282 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03283 dundi_discover(trans); 03284 } 03285 AST_LIST_UNLOCK(&peers); 03286 return 0; 03287 }
static int do_autokill | ( | const void * | data | ) | [static] |
Definition at line 3133 of file pbx_dundi.c.
References ast_eid_to_str(), ast_log(), dundi_transaction::autokillid, destroy_trans(), LOG_NOTICE, and dundi_transaction::them_eid.
Referenced by dundi_discover(), dundi_query(), and precache_trans().
03134 { 03135 struct dundi_transaction *trans = (struct dundi_transaction *)data; 03136 char eid_str[20]; 03137 ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 03138 ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); 03139 trans->autokillid = -1; 03140 destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */ 03141 return 0; 03142 }
static int do_qualify | ( | const void * | data | ) | [static] |
Definition at line 4298 of file pbx_dundi.c.
References qualify_peer(), and dundi_peer::qualifyid.
Referenced by qualify_peer().
04299 { 04300 struct dundi_peer *peer = (struct dundi_peer *)data; 04301 peer->qualifyid = -1; 04302 qualify_peer(peer, 0); 04303 return 0; 04304 }
static int do_register | ( | const void * | data | ) | [static] |
Definition at line 4272 of file pbx_dundi.c.
References ast_debug, ast_eid_to_str(), ast_log(), ast_sched_add(), ast_set_flag, create_transaction(), destroy_trans(), DUNDI_COMMAND_REGREQ, DUNDI_DEFAULT_VERSION, 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_NOTICE, dundi_peer::registerid, dundi_peer::regtrans, dundi_transaction::us_eid, and dundi_peer::us_eid.
Referenced by build_peer().
04273 { 04274 struct dundi_ie_data ied; 04275 struct dundi_peer *peer = (struct dundi_peer *)data; 04276 char eid_str[20]; 04277 char eid_str2[20]; 04278 ast_debug(1, "Register us as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), ast_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid)); 04279 peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data); 04280 /* Destroy old transaction if there is one */ 04281 if (peer->regtrans) 04282 destroy_trans(peer->regtrans, 0); 04283 peer->regtrans = create_transaction(peer); 04284 if (peer->regtrans) { 04285 ast_set_flag(peer->regtrans, FLAG_ISREG); 04286 memset(&ied, 0, sizeof(ied)); 04287 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 04288 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid); 04289 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration); 04290 dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied); 04291 04292 } else 04293 ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04294 04295 return 0; 04296 }
static int do_register_expire | ( | const void * | data | ) | [static] |
Definition at line 1301 of file pbx_dundi.c.
References dundi_peer::addr, ast_debug, ast_eid_to_str(), dundi_peer::eid, dundi_peer::lastms, and dundi_peer::registerexpire.
Referenced by handle_command_response(), and populate_addr().
01302 { 01303 struct dundi_peer *peer = (struct dundi_peer *)data; 01304 char eid_str[20]; 01305 ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01306 peer->registerexpire = -1; 01307 peer->lastms = 0; 01308 memset(&peer->addr, 0, sizeof(peer->addr)); 01309 return 0; 01310 }
static void drds_destroy | ( | struct dundi_result_datastore * | drds | ) | [static] |
Definition at line 3952 of file pbx_dundi.c.
References ast_free.
Referenced by drds_destroy_cb(), and dundi_query_read().
03953 { 03954 ast_free(drds); 03955 }
static void drds_destroy_cb | ( | void * | data | ) | [static] |
Definition at line 3957 of file pbx_dundi.c.
References drds_destroy().
03958 { 03959 struct dundi_result_datastore *drds = data; 03960 drds_destroy(drds); 03961 }
static int dundi_ack | ( | struct dundi_transaction * | trans, | |
int | final | |||
) | [static] |
Definition at line 440 of file pbx_dundi.c.
References DUNDI_COMMAND_ACK, and dundi_send().
Referenced by handle_command_response(), and handle_frame().
00441 { 00442 return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL); 00443 }
static int dundi_answer_entity | ( | struct dundi_transaction * | trans, | |
struct dundi_ies * | ies, | |||
char * | ccontext | |||
) | [static] |
Definition at line 791 of file pbx_dundi.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, ast_log(), ast_pthread_create_detached, dundi_ies::called_context, dundi_query_state::called_context, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_EIDRESPONSE, 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, LOG_WARNING, dundi_ies::reqeid, dundi_query_state::reqeid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.
Referenced by handle_command_response().
00792 { 00793 struct dundi_query_state *st; 00794 int totallen; 00795 int x; 00796 int skipfirst=0; 00797 char eid_str[20]; 00798 char *s; 00799 pthread_t lookupthread; 00800 00801 if (ies->eidcount > 1) { 00802 /* Since it is a requirement that the first EID is the authenticating host 00803 and the last EID is the root, it is permissible that the first and last EID 00804 could be the same. In that case, we should go ahead copy only the "root" section 00805 since we will not need it for authentication. */ 00806 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 00807 skipfirst = 1; 00808 } 00809 totallen = sizeof(struct dundi_query_state); 00810 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 00811 st = ast_calloc(1, totallen); 00812 if (st) { 00813 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); 00814 memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid)); 00815 st->trans = trans; 00816 st->ttl = ies->ttl - 1; 00817 if (st->ttl < 0) 00818 st->ttl = 0; 00819 s = st->fluffy; 00820 for (x=skipfirst;ies->eids[x];x++) { 00821 st->eids[x-skipfirst] = (dundi_eid *)s; 00822 *st->eids[x-skipfirst] = *ies->eids[x]; 00823 s += sizeof(dundi_eid); 00824 } 00825 ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context); 00826 00827 trans->thread = 1; 00828 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) { 00829 struct dundi_ie_data ied = { 0, }; 00830 trans->thread = 0; 00831 ast_log(LOG_WARNING, "Unable to create thread!\n"); 00832 ast_free(st); 00833 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 00834 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00835 return -1; 00836 } 00837 } else { 00838 struct dundi_ie_data ied = { 0, }; 00839 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 00840 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00841 return -1; 00842 } 00843 return 0; 00844 }
static int dundi_answer_query | ( | struct dundi_transaction * | trans, | |
struct dundi_ies * | ies, | |||
char * | ccontext | |||
) | [static] |
Definition at line 1069 of file pbx_dundi.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, 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_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, dundi_mapping::list, LOG_WARNING, dundi_query_state::maps, dundi_mapping::next, dundi_query_state::nocache, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.
Referenced by handle_command_response().
01070 { 01071 struct dundi_query_state *st; 01072 int totallen; 01073 int x; 01074 struct dundi_ie_data ied; 01075 char *s; 01076 struct dundi_mapping *cur; 01077 int mapcount = 0; 01078 int skipfirst = 0; 01079 01080 pthread_t lookupthread; 01081 totallen = sizeof(struct dundi_query_state); 01082 /* Count matching map entries */ 01083 AST_LIST_TRAVERSE(&mappings, cur, list) { 01084 if (!strcasecmp(cur->dcontext, ccontext)) 01085 mapcount++; 01086 } 01087 /* If no maps, return -1 immediately */ 01088 if (!mapcount) 01089 return -1; 01090 01091 if (ies->eidcount > 1) { 01092 /* Since it is a requirement that the first EID is the authenticating host 01093 and the last EID is the root, it is permissible that the first and last EID 01094 could be the same. In that case, we should go ahead copy only the "root" section 01095 since we will not need it for authentication. */ 01096 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 01097 skipfirst = 1; 01098 } 01099 01100 totallen += mapcount * sizeof(struct dundi_mapping); 01101 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 01102 st = ast_calloc(1, totallen); 01103 if (st) { 01104 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); 01105 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); 01106 st->trans = trans; 01107 st->ttl = ies->ttl - 1; 01108 st->nocache = ies->cbypass; 01109 if (st->ttl < 0) 01110 st->ttl = 0; 01111 s = st->fluffy; 01112 for (x=skipfirst;ies->eids[x];x++) { 01113 st->eids[x-skipfirst] = (dundi_eid *)s; 01114 *st->eids[x-skipfirst] = *ies->eids[x]; 01115 st->directs[x-skipfirst] = ies->eid_direct[x]; 01116 s += sizeof(dundi_eid); 01117 } 01118 /* Append mappings */ 01119 x = 0; 01120 st->maps = (struct dundi_mapping *)s; 01121 AST_LIST_TRAVERSE(&mappings, cur, list) { 01122 if (!strcasecmp(cur->dcontext, ccontext)) { 01123 if (x < mapcount) { 01124 st->maps[x] = *cur; 01125 st->maps[x].list.next = NULL; 01126 x++; 01127 } 01128 } 01129 } 01130 st->nummaps = mapcount; 01131 ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context); 01132 trans->thread = 1; 01133 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) { 01134 trans->thread = 0; 01135 ast_log(LOG_WARNING, "Unable to create thread!\n"); 01136 ast_free(st); 01137 memset(&ied, 0, sizeof(ied)); 01138 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 01139 dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 01140 return -1; 01141 } 01142 } else { 01143 ast_log(LOG_WARNING, "Out of memory!\n"); 01144 memset(&ied, 0, sizeof(ied)); 01145 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 01146 dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 01147 return -1; 01148 } 01149 return 0; 01150 }
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 4547 of file pbx_dundi.c.
References DUNDI_FLAG_CANMATCH, and dundi_helper().
04548 { 04549 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH); 04550 }
static void dundi_debug_output | ( | const char * | data | ) | [static] |
Definition at line 347 of file pbx_dundi.c.
References ast_verbose.
Referenced by load_module().
00348 { 00349 if (dundidebug) 00350 ast_verbose("%s", data); 00351 }
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 1384 of file pbx_dundi.c.
References ast_alloca, ast_debug, dundi_transaction::dcx, decrypt_memcpy(), dundi_encblock::encdata, and dundi_encblock::iv.
Referenced by handle_command_response().
01385 { 01386 int space = *dstlen; 01387 unsigned long bytes; 01388 struct dundi_hdr *h; 01389 unsigned char *decrypt_space; 01390 decrypt_space = ast_alloca(srclen); 01391 decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx); 01392 /* Setup header */ 01393 h = (struct dundi_hdr *)dst; 01394 *h = *ohdr; 01395 bytes = space - 6; 01396 if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) { 01397 ast_debug(1, "Ouch, uncompress failed :(\n"); 01398 return NULL; 01399 } 01400 /* Update length */ 01401 *dstlen = bytes + 6; 01402 /* Return new header */ 01403 return h; 01404 }
static int dundi_discover | ( | struct dundi_transaction * | trans | ) | [static] |
Definition at line 3166 of file pbx_dundi.c.
References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::cbypass, dundi_request::dcontext, do_autokill(), DUNDI_COMMAND_DPDISCOVER, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append(), dundi_ie_append_eid(), dundi_ie_append_eid_appropriately(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CACHEBYPASS, DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_CALLED_NUMBER, DUNDI_IE_EID_DIRECT, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, dundi_request::number, dundi_transaction::parent, dundi_transaction::ttl, and dundi_transaction::us_eid.
Referenced by discover_transactions().
03167 { 03168 struct dundi_ie_data ied; 03169 int x; 03170 if (!trans->parent) { 03171 ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); 03172 return -1; 03173 } 03174 memset(&ied, 0, sizeof(ied)); 03175 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03176 if (!dundi_eid_zero(&trans->us_eid)) 03177 dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid); 03178 for (x=0;x<trans->eidcount;x++) 03179 dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid); 03180 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); 03181 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03182 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03183 if (trans->parent->cbypass) 03184 dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS); 03185 if (trans->autokilltimeout) 03186 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03187 return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied); 03188 }
static char* dundi_do_lookup | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2420 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_result::dest, dundi_flags2str(), dundi_lookup(), dundi_result::eid_str, dundi_result::expiration, ast_cli_args::fd, sort_results(), dundi_result::tech, ast_cli_entry::usage, and dundi_result::weight.
02421 { 02422 int res; 02423 char tmp[256]; 02424 char fs[80] = ""; 02425 char *context; 02426 int x; 02427 int bypass = 0; 02428 struct dundi_result dr[MAX_RESULTS]; 02429 struct timeval start; 02430 switch (cmd) { 02431 case CLI_INIT: 02432 e->command = "dundi lookup"; 02433 e->usage = 02434 "Usage: dundi lookup <number>[@context] [bypass]\n" 02435 " Lookup the given number within the given DUNDi context\n" 02436 "(or e164 if none is specified). Bypasses cache if 'bypass'\n" 02437 "keyword is specified.\n"; 02438 return NULL; 02439 case CLI_GENERATE: 02440 return NULL; 02441 } 02442 02443 if ((a->argc < 3) || (a->argc > 4)) 02444 return CLI_SHOWUSAGE; 02445 if (a->argc > 3) { 02446 if (!strcasecmp(a->argv[3], "bypass")) 02447 bypass=1; 02448 else 02449 return CLI_SHOWUSAGE; 02450 } 02451 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02452 context = strchr(tmp, '@'); 02453 if (context) { 02454 *context = '\0'; 02455 context++; 02456 } 02457 start = ast_tvnow(); 02458 res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass); 02459 02460 if (res < 0) 02461 ast_cli(a->fd, "DUNDi lookup returned error.\n"); 02462 else if (!res) 02463 ast_cli(a->fd, "DUNDi lookup returned no results.\n"); 02464 else 02465 sort_results(dr, res); 02466 for (x=0;x<res;x++) { 02467 ast_cli(a->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)); 02468 ast_cli(a->fd, " from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration); 02469 } 02470 ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start)); 02471 return CLI_SUCCESS; 02472 }
static char* dundi_do_precache | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2474 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_tvdiff_ms(), ast_tvnow(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache(), ast_cli_args::fd, and ast_cli_entry::usage.
02475 { 02476 int res; 02477 char tmp[256]; 02478 char *context; 02479 struct timeval start; 02480 switch (cmd) { 02481 case CLI_INIT: 02482 e->command = "dundi precache"; 02483 e->usage = 02484 "Usage: dundi precache <number>[@context]\n" 02485 " Lookup the given number within the given DUNDi context\n" 02486 "(or e164 if none is specified) and precaches the results to any\n" 02487 "upstream DUNDi push servers.\n"; 02488 return NULL; 02489 case CLI_GENERATE: 02490 return NULL; 02491 } 02492 if ((a->argc < 3) || (a->argc > 3)) 02493 return CLI_SHOWUSAGE; 02494 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02495 context = strchr(tmp, '@'); 02496 if (context) { 02497 *context = '\0'; 02498 context++; 02499 } 02500 start = ast_tvnow(); 02501 res = dundi_precache(context, tmp); 02502 02503 if (res < 0) 02504 ast_cli(a->fd, "DUNDi precache returned error.\n"); 02505 else if (!res) 02506 ast_cli(a->fd, "DUNDi precache returned no error.\n"); 02507 ast_cli(a->fd, "DUNDi lookup completed in %" PRIi64 " ms\n", ast_tvdiff_ms(ast_tvnow(), start)); 02508 return CLI_SUCCESS; 02509 }
static char* dundi_do_query | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2511 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_str_to_eid(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_entity_info::country, dundi_query_eid(), dundi_entity_info::email, ast_cli_args::fd, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_entity_info::phone, dundi_entity_info::stateprov, and ast_cli_entry::usage.
02512 { 02513 int res; 02514 char tmp[256]; 02515 char *context; 02516 dundi_eid eid; 02517 struct dundi_entity_info dei; 02518 switch (cmd) { 02519 case CLI_INIT: 02520 e->command = "dundi query"; 02521 e->usage = 02522 "Usage: dundi query <entity>[@context]\n" 02523 " Attempts to retrieve contact information for a specific\n" 02524 "DUNDi entity identifier (EID) within a given DUNDi context (or\n" 02525 "e164 if none is specified).\n"; 02526 return NULL; 02527 case CLI_GENERATE: 02528 return NULL; 02529 } 02530 if ((a->argc < 3) || (a->argc > 3)) 02531 return CLI_SHOWUSAGE; 02532 if (ast_str_to_eid(&eid, a->argv[2])) { 02533 ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]); 02534 return CLI_SHOWUSAGE; 02535 } 02536 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02537 context = strchr(tmp, '@'); 02538 if (context) { 02539 *context = '\0'; 02540 context++; 02541 } 02542 res = dundi_query_eid(&dei, context, eid); 02543 if (res < 0) 02544 ast_cli(a->fd, "DUNDi Query EID returned error.\n"); 02545 else if (!res) 02546 ast_cli(a->fd, "DUNDi Query EID returned no results.\n"); 02547 else { 02548 ast_cli(a->fd, "DUNDi Query EID succeeded:\n"); 02549 ast_cli(a->fd, "Department: %s\n", dei.orgunit); 02550 ast_cli(a->fd, "Organization: %s\n", dei.org); 02551 ast_cli(a->fd, "City/Locality: %s\n", dei.locality); 02552 ast_cli(a->fd, "State/Province: %s\n", dei.stateprov); 02553 ast_cli(a->fd, "Country: %s\n", dei.country); 02554 ast_cli(a->fd, "E-mail: %s\n", dei.email); 02555 ast_cli(a->fd, "Phone: %s\n", dei.phone); 02556 ast_cli(a->fd, "IP Address: %s\n", dei.ipaddr); 02557 } 02558 return CLI_SUCCESS; 02559 }
static int dundi_encrypt | ( | struct dundi_transaction * | trans, | |
struct dundi_packet * | pack | |||
) | [static] |
Definition at line 1406 of file pbx_dundi.c.
References ast_alloca, ast_debug, ast_log(), ast_set_flag, ast_test_flag, dundi_ie_data::buf, build_iv(), dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dcx, DUNDI_COMMAND_ENCRYPT, dundi_ie_append_eid(), dundi_ie_append_encdata(), dundi_ie_append_int(), dundi_ie_append_raw(), DUNDI_IE_EID, DUNDI_IE_ENCDATA, DUNDI_IE_KEYCRC32, DUNDI_IE_SHAREDKEY, DUNDI_IE_SIGNATURE, dundi_transaction::ecx, encrypt_memcpy(), find_peer(), FLAG_SENDFULLKEY, dundi_packet::h, dundi_hdr::ies, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_hdr::oseqno, dundi_ie_data::pos, dundi_peer::sentfullkey, dundi_transaction::them_eid, dundi_peer::txenckey, update_key(), dundi_peer::us_dcx, dundi_peer::us_ecx, dundi_transaction::us_eid, and dundi_peer::us_keycrc32.
Referenced by dundi_send().
01407 { 01408 unsigned char *compress_space; 01409 int len; 01410 int res; 01411 unsigned long bytes; 01412 struct dundi_ie_data ied; 01413 struct dundi_peer *peer; 01414 unsigned char iv[16]; 01415 len = pack->datalen + pack->datalen / 100 + 42; 01416 compress_space = ast_alloca(len); 01417 memset(compress_space, 0, len); 01418 /* We care about everthing save the first 6 bytes of header */ 01419 bytes = len; 01420 res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6); 01421 if (res != Z_OK) { 01422 ast_debug(1, "Ouch, compression failed!\n"); 01423 return -1; 01424 } 01425 memset(&ied, 0, sizeof(ied)); 01426 /* Say who we are */ 01427 if (!pack->h->iseqno && !pack->h->oseqno) { 01428 /* Need the key in the first copy */ 01429 if (!(peer = find_peer(&trans->them_eid))) 01430 return -1; 01431 if (update_key(peer)) 01432 return -1; 01433 if (!peer->sentfullkey) 01434 ast_set_flag(trans, FLAG_SENDFULLKEY); 01435 /* Append key data */ 01436 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 01437 if (ast_test_flag(trans, FLAG_SENDFULLKEY)) { 01438 dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); 01439 dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); 01440 } else { 01441 dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32); 01442 } 01443 /* Setup contexts */ 01444 trans->ecx = peer->us_ecx; 01445 trans->dcx = peer->us_dcx; 01446 01447 /* We've sent the full key */ 01448 peer->sentfullkey = 1; 01449 } 01450 /* Build initialization vector */ 01451 build_iv(iv); 01452 /* Add the field, rounded up to 16 bytes */ 01453 dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16); 01454 /* Copy the data */ 01455 if ((ied.pos + bytes) >= sizeof(ied.buf)) { 01456 ast_log(LOG_NOTICE, "Final packet too large!\n"); 01457 return -1; 01458 } 01459 encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx); 01460 ied.pos += ((bytes + 15) / 16) * 16; 01461 /* Reconstruct header */ 01462 pack->datalen = sizeof(struct dundi_hdr); 01463 pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT; 01464 pack->h->cmdflags = 0; 01465 memcpy(pack->h->ies, ied.buf, ied.pos); 01466 pack->datalen += ied.pos; 01467 return 0; 01468 }
static void dundi_error_output | ( | const char * | data | ) | [static] |
Definition at line 353 of file pbx_dundi.c.
References ast_log(), and LOG_WARNING.
Referenced by load_module().
00354 { 00355 ast_log(LOG_WARNING, "%s", data); 00356 }
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 4552 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(), S_OR, and sort_results().
04553 { 04554 struct dundi_result results[MAX_RESULTS]; 04555 int res; 04556 int x=0; 04557 char req[1024]; 04558 const char *dundiargs; 04559 struct ast_app *dial; 04560 04561 if (!strncasecmp(context, "macro-", 6)) { 04562 if (!chan) { 04563 ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); 04564 return -1; 04565 } 04566 /* If done as a macro, use macro extension */ 04567 if (!strcasecmp(exten, "s")) { 04568 exten = pbx_builtin_getvar_helper(chan, "ARG1"); 04569 if (ast_strlen_zero(exten)) 04570 exten = chan->macroexten; 04571 if (ast_strlen_zero(exten)) 04572 exten = chan->exten; 04573 if (ast_strlen_zero(exten)) { 04574 ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); 04575 return -1; 04576 } 04577 } 04578 if (ast_strlen_zero(data)) 04579 data = "e164"; 04580 } else { 04581 if (ast_strlen_zero(data)) 04582 data = context; 04583 } 04584 res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); 04585 if (res > 0) { 04586 sort_results(results, res); 04587 for (x=0;x<res;x++) { 04588 if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) { 04589 if (!--priority) 04590 break; 04591 } 04592 } 04593 } 04594 if (x < res) { 04595 /* Got a hit! */ 04596 dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS"); 04597 snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest, 04598 S_OR(dundiargs, "")); 04599 dial = pbx_findapp("Dial"); 04600 if (dial) 04601 res = pbx_exec(chan, dial, req); 04602 } else 04603 res = -1; 04604 return res; 04605 }
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 4542 of file pbx_dundi.c.
References DUNDI_FLAG_EXISTS, and dundi_helper().
04543 { 04544 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS); 04545 }
static char* dundi_flush | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2322 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_db_deltree(), ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DUNDI_TIMING_HISTORY, ast_cli_args::fd, dundi_peer::lookups, dundi_peer::lookuptimes, and ast_cli_entry::usage.
02323 { 02324 int stats = 0; 02325 switch (cmd) { 02326 case CLI_INIT: 02327 e->command = "dundi flush [stats]"; 02328 e->usage = 02329 "Usage: dundi flush [stats]\n" 02330 " Flushes DUNDi answer cache, used primarily for debug. If\n" 02331 "'stats' is present, clears timer statistics instead of normal\n" 02332 "operation.\n"; 02333 return NULL; 02334 case CLI_GENERATE: 02335 return NULL; 02336 } 02337 if ((a->argc < 2) || (a->argc > 3)) 02338 return CLI_SHOWUSAGE; 02339 if (a->argc > 2) { 02340 if (!strcasecmp(a->argv[2], "stats")) 02341 stats = 1; 02342 else 02343 return CLI_SHOWUSAGE; 02344 } 02345 if (stats) { 02346 /* Flush statistics */ 02347 struct dundi_peer *p; 02348 int x; 02349 AST_LIST_LOCK(&peers); 02350 AST_LIST_TRAVERSE(&peers, p, list) { 02351 for (x = 0;x < DUNDI_TIMING_HISTORY; x++) { 02352 if (p->lookups[x]) 02353 ast_free(p->lookups[x]); 02354 p->lookups[x] = NULL; 02355 p->lookuptimes[x] = 0; 02356 } 02357 p->avgms = 0; 02358 } 02359 AST_LIST_UNLOCK(&peers); 02360 } else { 02361 ast_db_deltree("dundi/cache", NULL); 02362 ast_cli(a->fd, "DUNDi Cache Flushed\n"); 02363 } 02364 return CLI_SUCCESS; 02365 }
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 4503 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().
04504 { 04505 struct dundi_result results[MAX_RESULTS]; 04506 int res; 04507 int x; 04508 int found = 0; 04509 if (!strncasecmp(context, "macro-", 6)) { 04510 if (!chan) { 04511 ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); 04512 return -1; 04513 } 04514 /* If done as a macro, use macro extension */ 04515 if (!strcasecmp(exten, "s")) { 04516 exten = pbx_builtin_getvar_helper(chan, "ARG1"); 04517 if (ast_strlen_zero(exten)) 04518 exten = chan->macroexten; 04519 if (ast_strlen_zero(exten)) 04520 exten = chan->exten; 04521 if (ast_strlen_zero(exten)) { 04522 ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); 04523 return -1; 04524 } 04525 } 04526 if (ast_strlen_zero(data)) 04527 data = "e164"; 04528 } else { 04529 if (ast_strlen_zero(data)) 04530 data = context; 04531 } 04532 res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); 04533 for (x=0;x<res;x++) { 04534 if (ast_test_flag(results + x, flag)) 04535 found++; 04536 } 04537 if (found >= priority) 04538 return 1; 04539 return 0; 04540 }
static void dundi_ie_append_eid_appropriately | ( | struct dundi_ie_data * | ied, | |
char * | context, | |||
dundi_eid * | eid, | |||
dundi_eid * | us | |||
) | [static] |
Definition at line 3144 of file pbx_dundi.c.
References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_ie_append_eid(), DUNDI_IE_EID, DUNDI_IE_EID_DIRECT, dundi_peer::eid, has_permission(), and dundi_peer::include.
Referenced by dundi_discover().
03145 { 03146 struct dundi_peer *p; 03147 if (!ast_eid_cmp(eid, us)) { 03148 dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); 03149 return; 03150 } 03151 AST_LIST_LOCK(&peers); 03152 AST_LIST_TRAVERSE(&peers, p, list) { 03153 if (!ast_eid_cmp(&p->eid, eid)) { 03154 if (has_permission(&p->include, context)) 03155 dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); 03156 else 03157 dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); 03158 break; 03159 } 03160 } 03161 if (!p) 03162 dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); 03163 AST_LIST_UNLOCK(&peers); 03164 }
int dundi_lookup | ( | struct dundi_result * | result, | |
int | maxret, | |||
struct ast_channel * | chan, | |||
const char * | dcontext, | |||
const char * | number, | |||
int | nocache | |||
) |
Lookup the given number in the given dundi context. Lookup number in a given dundi context (if unspecified use e164), the given callerid (if specified) and return up to maxret results in the array specified.
the | number of results found. | |
-1 | on a hangup of the channel. |
Definition at line 3678 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(), dundi_query_read(), and dundifunc_read().
03679 { 03680 struct dundi_hint_metadata hmd; 03681 dundi_eid *avoid[1] = { NULL, }; 03682 int direct[1] = { 0, }; 03683 int expiration = dundi_cache_time; 03684 memset(&hmd, 0, sizeof(hmd)); 03685 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 03686 return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct); 03687 }
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 3576 of file pbx_dundi.c.
References abort_request(), ast_check_hangup(), ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_EMPTY, ast_log(), ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), 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_FLUFF_TIME, DUNDI_HINT_TTL_EXPIRED, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, register_request(), dundi_request::respcount, dundi_request::root_eid, dundi_request::trans, and unregister_request().
Referenced by dundi_lookup(), dundi_lookup_thread(), and precache_trans().
03577 { 03578 int res; 03579 struct dundi_request dr, *pending; 03580 dundi_eid *rooteid=NULL; 03581 int x; 03582 int ttlms; 03583 int ms; 03584 int foundcache; 03585 int skipped=0; 03586 int order=0; 03587 char eid_str[20]; 03588 struct timeval start; 03589 03590 /* Don't do anthing for a hungup channel */ 03591 if (chan && ast_check_hangup(chan)) 03592 return 0; 03593 03594 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03595 03596 for (x=0;avoid[x];x++) 03597 rooteid = avoid[x]; 03598 /* Now perform real check */ 03599 memset(&dr, 0, sizeof(dr)); 03600 if (pipe(dr.pfds)) { 03601 ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno)); 03602 return -1; 03603 } 03604 dr.dr = result; 03605 dr.hmd = hmd; 03606 dr.maxcount = maxret; 03607 dr.expiration = *expiration; 03608 dr.cbypass = cbypass; 03609 dr.crc32 = avoid_crc32(avoid); 03610 ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); 03611 ast_copy_string(dr.number, number, sizeof(dr.number)); 03612 if (rooteid) 03613 dr.root_eid = *rooteid; 03614 res = register_request(&dr, &pending); 03615 if (res) { 03616 /* Already a request */ 03617 if (rooteid && !ast_eid_cmp(&dr.root_eid, &pending->root_eid)) { 03618 /* This is on behalf of someone else. Go ahead and close this out since 03619 they'll get their answer anyway. */ 03620 ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n", 03621 dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid)); 03622 close(dr.pfds[0]); 03623 close(dr.pfds[1]); 03624 return -2; 03625 } else { 03626 /* Wait for the cache to populate */ 03627 ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n", 03628 dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid)); 03629 start = ast_tvnow(); 03630 while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) { 03631 /* XXX Would be nice to have a way to poll/select here XXX */ 03632 /* XXX this is a busy wait loop!!! */ 03633 usleep(1); 03634 } 03635 /* Continue on as normal, our cache should kick in */ 03636 } 03637 } 03638 /* Create transactions */ 03639 do { 03640 order = skipped; 03641 skipped = 0; 03642 foundcache = 0; 03643 build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct); 03644 } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans)); 03645 /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't 03646 do this earlier because we didn't know if we were going to have transactions 03647 or not. */ 03648 if (!ttl) { 03649 ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); 03650 abort_request(&dr); 03651 unregister_request(&dr); 03652 close(dr.pfds[0]); 03653 close(dr.pfds[1]); 03654 return 0; 03655 } 03656 03657 /* Optimize transactions */ 03658 optimize_transactions(&dr, order); 03659 /* Actually perform transactions */ 03660 discover_transactions(&dr); 03661 /* Wait for transaction to come back */ 03662 start = ast_tvnow(); 03663 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) { 03664 ms = 100; 03665 ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); 03666 } 03667 if (chan && ast_check_hangup(chan)) 03668 ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext); 03669 cancel_request(&dr); 03670 unregister_request(&dr); 03671 res = dr.respcount; 03672 *expiration = dr.expiration; 03673 close(dr.pfds[0]); 03674 close(dr.pfds[1]); 03675 return res; 03676 }
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 562 of file pbx_dundi.c.
References ast_canmatch_extension(), ast_clear_flag, ast_clear_flag_nonstd, ast_copy_flags, ast_copy_string(), ast_eid_to_str(), 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_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, get_mapping_weight(), dundi_mapping::lcontext, dundi_mapping::options, pbx_substitute_variables_varshead(), dundi_result::tech, dundi_mapping::tech, tech2str(), dundi_result::techint, and dundi_result::weight.
Referenced by dundi_lookup_thread(), and precache_trans().
00563 { 00564 struct ast_flags flags = {0}; 00565 int x; 00566 if (!ast_strlen_zero(map->lcontext)) { 00567 if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL)) 00568 ast_set_flag(&flags, DUNDI_FLAG_EXISTS); 00569 if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL)) 00570 ast_set_flag(&flags, DUNDI_FLAG_CANMATCH); 00571 if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL)) 00572 ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE); 00573 if (ast_ignore_pattern(map->lcontext, called_number)) 00574 ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT); 00575 00576 /* Clearly we can't say 'don't ask' anymore if we found anything... */ 00577 if (ast_test_flag(&flags, AST_FLAGS_ALL)) 00578 ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK); 00579 00580 if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) { 00581 /* Skip partial answers */ 00582 ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH); 00583 } 00584 if (ast_test_flag(&flags, AST_FLAGS_ALL)) { 00585 struct varshead headp; 00586 struct ast_var_t *newvariable; 00587 ast_set_flag(&flags, map->options & 0xffff); 00588 ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL); 00589 dr[anscnt].techint = map->tech; 00590 dr[anscnt].weight = get_mapping_weight(map); 00591 dr[anscnt].expiration = dundi_cache_time; 00592 ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech)); 00593 dr[anscnt].eid = *us_eid; 00594 ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid); 00595 if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) { 00596 AST_LIST_HEAD_INIT_NOLOCK(&headp); 00597 if ((newvariable = ast_var_assign("NUMBER", called_number))) { 00598 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00599 } 00600 if ((newvariable = ast_var_assign("EID", dr[anscnt].eid_str))) { 00601 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00602 } 00603 if ((newvariable = ast_var_assign("SECRET", cursecret))) { 00604 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00605 } 00606 if ((newvariable = ast_var_assign("IPADDR", ipaddr))) { 00607 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00608 } 00609 pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest)); 00610 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries))) 00611 ast_var_delete(newvariable); 00612 } else 00613 dr[anscnt].dest[0] = '\0'; 00614 anscnt++; 00615 } else { 00616 /* No answers... Find the fewest number of digits from the 00617 number for which we have no answer. */ 00618 char tmp[AST_MAX_EXTENSION + 1] = ""; 00619 for (x = 0; x < (sizeof(tmp) - 1); x++) { 00620 tmp[x] = called_number[x]; 00621 if (!tmp[x]) 00622 break; 00623 if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) { 00624 /* Oops found something we can't match. If this is longer 00625 than the running hint, we have to consider it */ 00626 if (strlen(tmp) > strlen(hmd->exten)) { 00627 ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten)); 00628 } 00629 break; 00630 } 00631 } 00632 } 00633 } 00634 return anscnt; 00635 }
static void* dundi_lookup_thread | ( | void * | data | ) | [static] |
Definition at line 639 of file pbx_dundi.c.
References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, 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_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_hint_metadata::flags, dundi_query_state::maps, dundi_query_state::nocache, dundi_query_state::nummaps, dundi_transaction::thread, dundi_query_state::trans, dundi_query_state::ttl, dundi_transaction::us_eid, and dundi_result::weight.
Referenced by dundi_answer_query().
00640 { 00641 struct dundi_query_state *st = data; 00642 struct dundi_result dr[MAX_RESULTS]; 00643 struct dundi_ie_data ied; 00644 struct dundi_hint_metadata hmd; 00645 char eid_str[20]; 00646 int res, x; 00647 int ouranswers=0; 00648 int max = 999999; 00649 int expiration = dundi_cache_time; 00650 00651 ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 00652 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00653 memset(&ied, 0, sizeof(ied)); 00654 memset(&dr, 0, sizeof(dr)); 00655 memset(&hmd, 0, sizeof(hmd)); 00656 /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */ 00657 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 00658 for (x=0;x<st->nummaps;x++) 00659 ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd); 00660 if (ouranswers < 0) 00661 ouranswers = 0; 00662 for (x=0;x<ouranswers;x++) { 00663 if (dr[x].weight < max) 00664 max = dr[x].weight; 00665 } 00666 00667 if (max) { 00668 /* If we do not have a canonical result, keep looking */ 00669 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); 00670 if (res > 0) { 00671 /* Append answer in result */ 00672 ouranswers += res; 00673 } else { 00674 if ((res < -1) && (!ouranswers)) 00675 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending"); 00676 } 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_debug(1, "Our transaction went away!\n"); 00684 st->trans->thread = 0; 00685 destroy_trans(st->trans, 0); 00686 } else { 00687 for (x=0;x<ouranswers;x++) { 00688 /* Add answers */ 00689 if (dr[x].expiration && (expiration > dr[x].expiration)) 00690 expiration = dr[x].expiration; 00691 dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); 00692 } 00693 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 00694 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); 00695 dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 00696 st->trans->thread = 0; 00697 } 00698 AST_LIST_UNLOCK(&peers); 00699 ast_free(st); 00700 return NULL; 00701 }
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 4607 of file pbx_dundi.c.
References DUNDI_FLAG_MATCHMORE, and dundi_helper().
04608 { 04609 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE); 04610 }
int dundi_precache | ( | const char * | context, | |
const char * | number | |||
) |
Pre-cache to push upstream peers.
Definition at line 3821 of file pbx_dundi.c.
References dundi_precache_internal().
Referenced by dundi_do_precache(), and process_precache().
03822 { 03823 dundi_eid *avoid[1] = { NULL, }; 03824 return dundi_precache_internal(context, number, dundi_ttl, avoid); 03825 }
static void dundi_precache_full | ( | void | ) | [static] |
Definition at line 3725 of file pbx_dundi.c.
References ast_get_context_name(), ast_get_extension_name(), AST_LIST_TRAVERSE, ast_log(), ast_rdlock_context(), 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().
03726 { 03727 struct dundi_mapping *cur; 03728 struct ast_context *con; 03729 struct ast_exten *e; 03730 03731 AST_LIST_TRAVERSE(&mappings, cur, list) { 03732 ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext); 03733 ast_rdlock_contexts(); 03734 con = NULL; 03735 while ((con = ast_walk_contexts(con))) { 03736 if (strcasecmp(cur->lcontext, ast_get_context_name(con))) 03737 continue; 03738 /* Found the match, now queue them all up */ 03739 ast_rdlock_context(con); 03740 e = NULL; 03741 while ((e = ast_walk_context_extensions(con, e))) 03742 reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0); 03743 ast_unlock_context(con); 03744 } 03745 ast_unlock_contexts(); 03746 } 03747 }
static int dundi_precache_internal | ( | const char * | context, | |
const char * | number, | |||
int | ttl, | |||
dundi_eid * | avoids[] | |||
) | [static] |
Definition at line 3749 of file pbx_dundi.c.
References ast_alloca, ast_copy_string(), ast_debug, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor_n_fd(), build_transactions(), cancel_request(), dundi_request::dcontext, dundi_request::dr, DUNDI_FLUFF_TIME, DUNDI_TTL_TIME, errno, dundi_request::expiration, dundi_request::hmd, LOG_NOTICE, LOG_WARNING, dundi_request::maxcount, dundi_request::number, optimize_transactions(), dundi_request::pfds, precache_transactions(), reschedule_precache(), and dundi_request::trans.
Referenced by dundi_precache(), and dundi_precache_thread().
03750 { 03751 struct dundi_request dr; 03752 struct dundi_hint_metadata hmd; 03753 struct dundi_result dr2[MAX_RESULTS]; 03754 struct timeval start; 03755 struct dundi_mapping *maps = NULL, *cur; 03756 int nummaps = 0; 03757 int foundanswers; 03758 int foundcache, skipped, ttlms, ms; 03759 if (!context) 03760 context = "e164"; 03761 ast_debug(1, "Precache internal (%s@%s)!\n", number, context); 03762 03763 AST_LIST_LOCK(&peers); 03764 AST_LIST_TRAVERSE(&mappings, cur, list) { 03765 if (!strcasecmp(cur->dcontext, context)) 03766 nummaps++; 03767 } 03768 if (nummaps) { 03769 maps = ast_alloca(nummaps * sizeof(*maps)); 03770 nummaps = 0; 03771 AST_LIST_TRAVERSE(&mappings, cur, list) { 03772 if (!strcasecmp(cur->dcontext, context)) 03773 maps[nummaps++] = *cur; 03774 } 03775 } 03776 AST_LIST_UNLOCK(&peers); 03777 if (!nummaps) { 03778 return -1; 03779 } 03780 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03781 memset(&dr2, 0, sizeof(dr2)); 03782 memset(&dr, 0, sizeof(dr)); 03783 memset(&hmd, 0, sizeof(hmd)); 03784 dr.dr = dr2; 03785 ast_copy_string(dr.number, number, sizeof(dr.number)); 03786 ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext)); 03787 dr.maxcount = MAX_RESULTS; 03788 dr.expiration = dundi_cache_time; 03789 dr.hmd = &hmd; 03790 dr.pfds[0] = dr.pfds[1] = -1; 03791 if (pipe(dr.pfds) < 0) { 03792 ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno)); 03793 return -1; 03794 } 03795 build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL); 03796 optimize_transactions(&dr, 0); 03797 foundanswers = 0; 03798 precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers); 03799 if (foundanswers) { 03800 if (dr.expiration > 0) 03801 reschedule_precache(dr.number, dr.dcontext, dr.expiration); 03802 else 03803 ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext); 03804 } 03805 start = ast_tvnow(); 03806 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) { 03807 if (dr.pfds[0] > -1) { 03808 ms = 100; 03809 ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); 03810 } else 03811 usleep(1); 03812 } 03813 cancel_request(&dr); 03814 if (dr.pfds[0] > -1) { 03815 close(dr.pfds[0]); 03816 close(dr.pfds[1]); 03817 } 03818 return 0; 03819 }
static void* dundi_precache_thread | ( | void * | data | ) | [static] |
Definition at line 703 of file pbx_dundi.c.
References ast_debug, ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_flag, ast_test_flag_nonstd, dundi_query_state::called_context, dundi_query_state::called_number, destroy_trans(), DUNDI_COMMAND_PRECACHERP, DUNDI_HINT_DONT_ASK, dundi_precache_internal(), dundi_send(), dundi_query_state::eids, dundi_hint_metadata::exten, FLAG_DEAD, dundi_transaction::thread, dundi_query_state::trans, and dundi_query_state::ttl.
Referenced by dundi_prop_precache().
00704 { 00705 struct dundi_query_state *st = data; 00706 struct dundi_ie_data ied; 00707 struct dundi_hint_metadata hmd; 00708 char eid_str[20]; 00709 00710 ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 00711 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00712 memset(&ied, 0, sizeof(ied)); 00713 00714 /* Now produce precache */ 00715 dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids); 00716 00717 AST_LIST_LOCK(&peers); 00718 /* Truncate if "don't ask" isn't present */ 00719 if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK)) 00720 hmd.exten[0] = '\0'; 00721 if (ast_test_flag(st->trans, FLAG_DEAD)) { 00722 ast_debug(1, "Our transaction went away!\n"); 00723 st->trans->thread = 0; 00724 destroy_trans(st->trans, 0); 00725 } else { 00726 dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 00727 st->trans->thread = 0; 00728 } 00729 AST_LIST_UNLOCK(&peers); 00730 ast_free(st); 00731 return NULL; 00732 }
static int dundi_prop_precache | ( | struct dundi_transaction * | trans, | |
struct dundi_ies * | ies, | |||
char * | ccontext | |||
) | [static] |
Definition at line 922 of file pbx_dundi.c.
References dundi_ies::anscount, dundi_ies::answers, ast_calloc, ast_clear_flag_nonstd, ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_TRAVERSE, ast_log(), ast_pthread_create_detached, 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_result::dest, dundi_query_state::directs, dundi_request::dr, DUNDI_CAUSE_GENERAL, DUNDI_COMMAND_PRECACHERP, DUNDI_HINT_DONT_ASK, DUNDI_HINT_UNAFFECTED, dundi_ie_append_cause(), DUNDI_IE_CAUSE, dundi_precache_thread(), dundi_send(), dundi_answer::eid, dundi_result::eid, dundi_ies::eid_direct, dundi_result::eid_str, dundi_ies::eidcount, dundi_query_state::eids, dundi_ies::eids, dundi_result::expiration, dundi_ies::expiration, dundi_request::expiration, dundi_answer::flags, dundi_result::flags, dundi_hint_metadata::flags, dundi_query_state::fluffy, dundi_ies::hint, dundi_request::hmd, dundi_mapping::list, LOG_NOTICE, LOG_WARNING, dundi_query_state::maps, dundi_request::maxcount, dundi_mapping::next, dundi_query_state::nocache, dundi_request::number, dundi_query_state::nummaps, dundi_transaction::parent, dundi_request::pfds, dundi_answer::protocol, dundi_request::respcount, dundi_result::tech, tech2str(), dundi_result::techint, dundi_transaction::them_eid, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, dundi_query_state::ttl, dundi_answer::weight, and dundi_result::weight.
Referenced by handle_command_response().
00923 { 00924 struct dundi_query_state *st; 00925 int totallen; 00926 int x,z; 00927 struct dundi_ie_data ied; 00928 char *s; 00929 struct dundi_result dr2[MAX_RESULTS]; 00930 struct dundi_request dr; 00931 struct dundi_hint_metadata hmd; 00932 00933 struct dundi_mapping *cur; 00934 int mapcount; 00935 int skipfirst = 0; 00936 00937 pthread_t lookupthread; 00938 00939 memset(&dr2, 0, sizeof(dr2)); 00940 memset(&dr, 0, sizeof(dr)); 00941 memset(&hmd, 0, sizeof(hmd)); 00942 00943 /* Forge request structure to hold answers for cache */ 00944 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 00945 dr.dr = dr2; 00946 dr.maxcount = MAX_RESULTS; 00947 dr.expiration = dundi_cache_time; 00948 dr.hmd = &hmd; 00949 dr.pfds[0] = dr.pfds[1] = -1; 00950 trans->parent = &dr; 00951 ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext)); 00952 ast_copy_string(dr.number, ies->called_number, sizeof(dr.number)); 00953 00954 for (x=0;x<ies->anscount;x++) { 00955 if (trans->parent->respcount < trans->parent->maxcount) { 00956 /* Make sure it's not already there */ 00957 for (z=0;z<trans->parent->respcount;z++) { 00958 if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) && 00959 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data)) 00960 break; 00961 } 00962 if (z == trans->parent->respcount) { 00963 /* Copy into parent responses */ 00964 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags); 00965 trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol; 00966 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight); 00967 trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid; 00968 if (ies->expiration > 0) 00969 trans->parent->dr[trans->parent->respcount].expiration = ies->expiration; 00970 else 00971 trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; 00972 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 00973 sizeof(trans->parent->dr[trans->parent->respcount].eid_str), 00974 &ies->answers[x]->eid); 00975 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data, 00976 sizeof(trans->parent->dr[trans->parent->respcount].dest)); 00977 ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol), 00978 sizeof(trans->parent->dr[trans->parent->respcount].tech)); 00979 trans->parent->respcount++; 00980 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 00981 } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) { 00982 /* Update weight if appropriate */ 00983 trans->parent->dr[z].weight = ies->answers[x]->weight; 00984 } 00985 } else 00986 ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n", 00987 trans->parent->number, trans->parent->dcontext); 00988 00989 } 00990 /* Save all the results (if any) we had. Even if no results, still cache lookup. */ 00991 cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1); 00992 if (ies->hint) 00993 cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration); 00994 00995 totallen = sizeof(struct dundi_query_state); 00996 /* Count matching map entries */ 00997 mapcount = 0; 00998 AST_LIST_TRAVERSE(&mappings, cur, list) { 00999 if (!strcasecmp(cur->dcontext, ccontext)) 01000 mapcount++; 01001 } 01002 01003 /* If no maps, return -1 immediately */ 01004 if (!mapcount) 01005 return -1; 01006 01007 if (ies->eidcount > 1) { 01008 /* Since it is a requirement that the first EID is the authenticating host 01009 and the last EID is the root, it is permissible that the first and last EID 01010 could be the same. In that case, we should go ahead copy only the "root" section 01011 since we will not need it for authentication. */ 01012 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 01013 skipfirst = 1; 01014 } 01015 01016 /* Prepare to run a query and then propagate that as necessary */ 01017 totallen += mapcount * sizeof(struct dundi_mapping); 01018 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 01019 st = ast_calloc(1, totallen); 01020 if (st) { 01021 ast_copy_string(st->called_context, dr.dcontext, sizeof(st->called_context)); 01022 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); 01023 st->trans = trans; 01024 st->ttl = ies->ttl - 1; 01025 st->nocache = ies->cbypass; 01026 if (st->ttl < 0) 01027 st->ttl = 0; 01028 s = st->fluffy; 01029 for (x=skipfirst;ies->eids[x];x++) { 01030 st->eids[x-skipfirst] = (dundi_eid *)s; 01031 *st->eids[x-skipfirst] = *ies->eids[x]; 01032 st->directs[x-skipfirst] = ies->eid_direct[x]; 01033 s += sizeof(dundi_eid); 01034 } 01035 /* Append mappings */ 01036 x = 0; 01037 st->maps = (struct dundi_mapping *)s; 01038 AST_LIST_TRAVERSE(&mappings, cur, list) { 01039 if (!strcasecmp(cur->dcontext, ccontext)) { 01040 if (x < mapcount) { 01041 st->maps[x] = *cur; 01042 st->maps[x].list.next = NULL; 01043 x++; 01044 } 01045 } 01046 } 01047 st->nummaps = mapcount; 01048 ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context); 01049 trans->thread = 1; 01050 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) { 01051 trans->thread = 0; 01052 ast_log(LOG_WARNING, "Unable to create thread!\n"); 01053 ast_free(st); 01054 memset(&ied, 0, sizeof(ied)); 01055 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 01056 dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 01057 return -1; 01058 } 01059 } else { 01060 ast_log(LOG_WARNING, "Out of memory!\n"); 01061 memset(&ied, 0, sizeof(ied)); 01062 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 01063 dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 01064 return -1; 01065 } 01066 return 0; 01067 }
static int dundi_query | ( | struct dundi_transaction * | trans | ) | [static] |
Definition at line 3256 of file pbx_dundi.c.
References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, do_autokill(), DUNDI_COMMAND_EIDQUERY, DUNDI_DEFAULT_VERSION, dundi_eid_zero(), dundi_ie_append_eid(), dundi_ie_append_short(), dundi_ie_append_str(), DUNDI_IE_CALLED_CONTEXT, DUNDI_IE_EID, DUNDI_IE_REQEID, DUNDI_IE_TTL, DUNDI_IE_VERSION, dundi_send(), dundi_transaction::eidcount, dundi_transaction::eids, LOG_WARNING, dundi_transaction::parent, dundi_request::query_eid, dundi_transaction::ttl, and dundi_transaction::us_eid.
Referenced by query_transactions().
03257 { 03258 struct dundi_ie_data ied; 03259 int x; 03260 if (!trans->parent) { 03261 ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n"); 03262 return -1; 03263 } 03264 memset(&ied, 0, sizeof(ied)); 03265 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03266 if (!dundi_eid_zero(&trans->us_eid)) 03267 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 03268 for (x=0;x<trans->eidcount;x++) 03269 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); 03270 dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid); 03271 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03272 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03273 if (trans->autokilltimeout) 03274 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03275 return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied); 03276 }
int dundi_query_eid | ( | struct dundi_entity_info * | dei, | |
const char * | dcontext, | |||
dundi_eid | eid | |||
) |
Retrieve information on a specific EID.
Definition at line 3874 of file pbx_dundi.c.
References dundi_query_eid_internal().
Referenced by dundi_do_query().
03875 { 03876 dundi_eid *avoid[1] = { NULL, }; 03877 struct dundi_hint_metadata hmd; 03878 memset(&hmd, 0, sizeof(hmd)); 03879 return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid); 03880 }
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 3827 of file pbx_dundi.c.
References ast_copy_string(), AST_LIST_EMPTY, ast_set_flag_nonstd, ast_tvdiff_ms(), ast_tvnow(), 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, dundi_request::root_eid, and dundi_request::trans.
Referenced by dundi_query_eid(), and dundi_query_thread().
03828 { 03829 int res; 03830 struct dundi_request dr; 03831 dundi_eid *rooteid=NULL; 03832 int x; 03833 int ttlms; 03834 int skipped=0; 03835 int foundcache=0; 03836 struct timeval start; 03837 03838 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03839 03840 for (x=0;avoid[x];x++) 03841 rooteid = avoid[x]; 03842 /* Now perform real check */ 03843 memset(&dr, 0, sizeof(dr)); 03844 dr.hmd = hmd; 03845 dr.dei = dei; 03846 dr.pfds[0] = dr.pfds[1] = -1; 03847 ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); 03848 memcpy(&dr.query_eid, eid, sizeof(dr.query_eid)); 03849 if (rooteid) 03850 dr.root_eid = *rooteid; 03851 /* Create transactions */ 03852 build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL); 03853 03854 /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't 03855 do this earlier because we didn't know if we were going to have transactions 03856 or not. */ 03857 if (!ttl) { 03858 ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); 03859 return 0; 03860 } 03861 03862 /* Optimize transactions */ 03863 optimize_transactions(&dr, 9999); 03864 /* Actually perform transactions */ 03865 query_transactions(&dr); 03866 /* Wait for transaction to come back */ 03867 start = ast_tvnow(); 03868 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) 03869 usleep(1); 03870 res = dr.respcount; 03871 return res; 03872 }
static int dundi_query_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3968 of file pbx_dundi.c.
References args, ARRAY_LEN, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_datastore::data, drds_destroy(), dundi_lookup(), dundi_query_opts, dundi_result_datastore::id, LOG_ERROR, LOG_WARNING, dundi_result_datastore::num_results, OPT_BYPASS_CACHE, parse(), dundi_result_datastore::results, and sort_results().
03969 { 03970 AST_DECLARE_APP_ARGS(args, 03971 AST_APP_ARG(number); 03972 AST_APP_ARG(context); 03973 AST_APP_ARG(options); 03974 ); 03975 struct ast_flags opts = { 0, }; 03976 char *parse; 03977 struct dundi_result_datastore *drds; 03978 struct ast_datastore *datastore; 03979 03980 if (ast_strlen_zero(data)) { 03981 ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n"); 03982 return -1; 03983 } 03984 03985 if (!chan) { 03986 ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n"); 03987 return -1; 03988 } 03989 03990 parse = ast_strdupa(data); 03991 03992 AST_STANDARD_APP_ARGS(args, parse); 03993 03994 if (!ast_strlen_zero(args.options)) 03995 ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options); 03996 03997 if (ast_strlen_zero(args.context)) 03998 args.context = "e164"; 03999 04000 if (!(drds = ast_calloc(1, sizeof(*drds)))) { 04001 return -1; 04002 } 04003 04004 drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1); 04005 snprintf(buf, len, "%u", drds->id); 04006 04007 if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) { 04008 drds_destroy(drds); 04009 return -1; 04010 } 04011 04012 datastore->data = drds; 04013 04014 drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, 04015 args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE)); 04016 04017 if (drds->num_results > 0) 04018 sort_results(drds->results, drds->num_results); 04019 04020 ast_channel_lock(chan); 04021 ast_channel_datastore_add(chan, datastore); 04022 ast_channel_unlock(chan); 04023 04024 return 0; 04025 }
static void* dundi_query_thread | ( | void * | data | ) | [static] |
Definition at line 736 of file pbx_dundi.c.
References ast_copy_string(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, AST_LIST_LOCK, AST_LIST_UNLOCK, 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_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, dundi_entity_info::ipaddr, dundi_entity_info::locality, dundi_entity_info::org, dundi_entity_info::orgunit, 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().
00737 { 00738 struct dundi_query_state *st = data; 00739 struct dundi_entity_info dei; 00740 struct dundi_ie_data ied; 00741 struct dundi_hint_metadata hmd; 00742 char eid_str[20]; 00743 int res; 00744 00745 ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 00746 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00747 memset(&ied, 0, sizeof(ied)); 00748 memset(&dei, 0, sizeof(dei)); 00749 memset(&hmd, 0, sizeof(hmd)); 00750 if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) { 00751 /* Ooh, it's us! */ 00752 ast_debug(1, "Neat, someone look for us!\n"); 00753 ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit)); 00754 ast_copy_string(dei.org, org, sizeof(dei.org)); 00755 ast_copy_string(dei.locality, locality, sizeof(dei.locality)); 00756 ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov)); 00757 ast_copy_string(dei.country, country, sizeof(dei.country)); 00758 ast_copy_string(dei.email, email, sizeof(dei.email)); 00759 ast_copy_string(dei.phone, phone, sizeof(dei.phone)); 00760 res = 1; 00761 } else { 00762 /* If we do not have a canonical result, keep looking */ 00763 res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids); 00764 } 00765 AST_LIST_LOCK(&peers); 00766 if (ast_test_flag(st->trans, FLAG_DEAD)) { 00767 ast_debug(1, "Our transaction went away!\n"); 00768 st->trans->thread = 0; 00769 destroy_trans(st->trans, 0); 00770 } else { 00771 if (res) { 00772 dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit); 00773 dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org); 00774 dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality); 00775 dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov); 00776 dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country); 00777 dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email); 00778 dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone); 00779 if (!ast_strlen_zero(dei.ipaddr)) 00780 dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr); 00781 } 00782 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 00783 dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00784 st->trans->thread = 0; 00785 } 00786 AST_LIST_UNLOCK(&peers); 00787 ast_free(st); 00788 return NULL; 00789 }
static void dundi_reject | ( | struct dundi_hdr * | h, | |
struct sockaddr_in * | sin | |||
) | [static] |
Definition at line 444 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().
00445 { 00446 struct { 00447 struct dundi_packet pack; 00448 struct dundi_hdr hdr; 00449 } tmp; 00450 struct dundi_transaction trans; 00451 /* Never respond to an INVALID with another INVALID */ 00452 if (h->cmdresp == DUNDI_COMMAND_INVALID) 00453 return; 00454 memset(&tmp, 0, sizeof(tmp)); 00455 memset(&trans, 0, sizeof(trans)); 00456 memcpy(&trans.addr, sin, sizeof(trans.addr)); 00457 tmp.hdr.strans = h->dtrans; 00458 tmp.hdr.dtrans = h->strans; 00459 tmp.hdr.iseqno = h->oseqno; 00460 tmp.hdr.oseqno = h->iseqno; 00461 tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID; 00462 tmp.hdr.cmdflags = 0; 00463 tmp.pack.h = (struct dundi_hdr *)tmp.pack.data; 00464 tmp.pack.datalen = sizeof(struct dundi_hdr); 00465 tmp.pack.parent = &trans; 00466 dundi_xmit(&tmp.pack); 00467 }
static int dundi_result_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4032 of file pbx_dundi.c.
References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_datastore::data, dundi_result::dest, LOG_ERROR, LOG_WARNING, dundi_result_datastore::num_results, parse(), dundi_result_datastore::results, and dundi_result::tech.
04033 { 04034 AST_DECLARE_APP_ARGS(args, 04035 AST_APP_ARG(id); 04036 AST_APP_ARG(resultnum); 04037 ); 04038 char *parse; 04039 unsigned int num; 04040 struct dundi_result_datastore *drds; 04041 struct ast_datastore *datastore; 04042 int res = -1; 04043 04044 if (ast_strlen_zero(data)) { 04045 ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n"); 04046 goto finish; 04047 } 04048 04049 if (!chan) { 04050 ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n"); 04051 goto finish; 04052 } 04053 04054 parse = ast_strdupa(data); 04055 04056 AST_STANDARD_APP_ARGS(args, parse); 04057 04058 if (ast_strlen_zero(args.id)) { 04059 ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n"); 04060 goto finish; 04061 } 04062 04063 if (ast_strlen_zero(args.resultnum)) { 04064 ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n"); 04065 goto finish; 04066 } 04067 04068 ast_channel_lock(chan); 04069 datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id); 04070 ast_channel_unlock(chan); 04071 04072 if (!datastore) { 04073 ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id); 04074 goto finish; 04075 } 04076 04077 drds = datastore->data; 04078 04079 if (!strcasecmp(args.resultnum, "getnum")) { 04080 snprintf(buf, len, "%u", drds->num_results); 04081 res = 0; 04082 goto finish; 04083 } 04084 04085 if (sscanf(args.resultnum, "%30u", &num) != 1) { 04086 ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n", 04087 args.resultnum); 04088 goto finish; 04089 } 04090 04091 if (num && num <= drds->num_results) { 04092 snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest); 04093 res = 0; 04094 } else 04095 ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id); 04096 04097 finish: 04098 return res; 04099 }
static int dundi_rexmit | ( | const void * | data | ) | [static] |
Definition at line 3039 of file pbx_dundi.c.
References dundi_transaction::addr, ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_test_flag, destroy_trans(), dundi_xmit(), FLAG_ISQUAL, dundi_packet::h, LOG_NOTICE, dundi_hdr::oseqno, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, and dundi_hdr::strans.
Referenced by dundi_send().
03040 { 03041 struct dundi_packet *pack = (struct dundi_packet *)data; 03042 int res; 03043 AST_LIST_LOCK(&peers); 03044 if (pack->retrans < 1) { 03045 pack->retransid = -1; 03046 if (!ast_test_flag(pack->parent, FLAG_ISQUAL)) 03047 ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 03048 ast_inet_ntoa(pack->parent->addr.sin_addr), 03049 ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans)); 03050 destroy_trans(pack->parent, 1); 03051 res = 0; 03052 } else { 03053 /* Decrement retransmission, try again */ 03054 pack->retrans--; 03055 dundi_xmit(pack); 03056 res = 1; 03057 } 03058 AST_LIST_UNLOCK(&peers); 03059 return res; 03060 }
static int dundi_send | ( | struct dundi_transaction * | trans, | |
int | cmdresp, | |||
int | flags, | |||
int | final, | |||
struct dundi_ie_data * | ied | |||
) | [static] |
Definition at line 3062 of file pbx_dundi.c.
References dundi_transaction::addr, dundi_transaction::aseqno, ast_calloc, ast_eid_to_str(), ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_sched_add(), ast_set_flag, ast_test_flag, dundi_hdr::cmdflags, dundi_hdr::cmdresp, dundi_packet::data, dundi_packet::datalen, dundi_transaction::dtrans, dundi_hdr::dtrans, DUNDI_COMMAND_ACK, DUNDI_COMMAND_DPDISCOVER, DUNDI_COMMAND_DPRESPONSE, DUNDI_COMMAND_EIDQUERY, DUNDI_COMMAND_EIDRESPONSE, DUNDI_COMMAND_FINAL, DUNDI_COMMAND_PRECACHERP, DUNDI_COMMAND_PRECACHERQ, DUNDI_COMMAND_REGREQ, DUNDI_COMMAND_REGRESPONSE, DUNDI_DEFAULT_RETRANS, dundi_encrypt(), dundi_rexmit(), dundi_showframe(), dundi_xmit(), FLAG_ENCRYPT, FLAG_FINAL, dundi_packet::h, dundi_hdr::ies, dundi_transaction::iseqno, dundi_hdr::iseqno, len(), LOG_NOTICE, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::packets, dundi_packet::parent, dundi_packet::retrans, dundi_packet::retransid, dundi_transaction::retranstimer, dundi_transaction::strans, dundi_hdr::strans, and dundi_transaction::them_eid.
Referenced by cancel_request(), do_register(), dundi_ack(), dundi_answer_entity(), dundi_answer_query(), dundi_discover(), dundi_lookup_thread(), dundi_precache_thread(), dundi_prop_precache(), dundi_query(), dundi_query_thread(), handle_command_response(), precache_trans(), and qualify_peer().
03063 { 03064 struct dundi_packet *pack; 03065 int res; 03066 int len; 03067 char eid_str[20]; 03068 len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0); 03069 /* Reserve enough space for encryption */ 03070 if (ast_test_flag(trans, FLAG_ENCRYPT)) 03071 len += 384; 03072 pack = ast_calloc(1, len); 03073 if (pack) { 03074 pack->h = (struct dundi_hdr *)(pack->data); 03075 if (cmdresp != DUNDI_COMMAND_ACK) { 03076 pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack); 03077 pack->retrans = DUNDI_DEFAULT_RETRANS - 1; 03078 AST_LIST_INSERT_HEAD(&trans->packets, pack, list); 03079 } 03080 pack->parent = trans; 03081 pack->h->strans = htons(trans->strans); 03082 pack->h->dtrans = htons(trans->dtrans); 03083 pack->h->iseqno = trans->iseqno; 03084 pack->h->oseqno = trans->oseqno; 03085 pack->h->cmdresp = cmdresp; 03086 pack->datalen = sizeof(struct dundi_hdr); 03087 if (ied) { 03088 memcpy(pack->h->ies, ied->buf, ied->pos); 03089 pack->datalen += ied->pos; 03090 } 03091 if (final) { 03092 pack->h->cmdresp |= DUNDI_COMMAND_FINAL; 03093 ast_set_flag(trans, FLAG_FINAL); 03094 } 03095 pack->h->cmdflags = flags; 03096 if (cmdresp != DUNDI_COMMAND_ACK) { 03097 trans->oseqno++; 03098 trans->oseqno = trans->oseqno % 256; 03099 } 03100 trans->aseqno = trans->iseqno; 03101 /* If we have their public key, encrypt */ 03102 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 03103 switch(cmdresp) { 03104 case DUNDI_COMMAND_REGREQ: 03105 case DUNDI_COMMAND_REGRESPONSE: 03106 case DUNDI_COMMAND_DPDISCOVER: 03107 case DUNDI_COMMAND_DPRESPONSE: 03108 case DUNDI_COMMAND_EIDQUERY: 03109 case DUNDI_COMMAND_EIDRESPONSE: 03110 case DUNDI_COMMAND_PRECACHERQ: 03111 case DUNDI_COMMAND_PRECACHERP: 03112 if (dundidebug) 03113 dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr)); 03114 res = dundi_encrypt(trans, pack); 03115 break; 03116 default: 03117 res = 0; 03118 } 03119 } else 03120 res = 0; 03121 if (!res) 03122 res = dundi_xmit(pack); 03123 if (res) 03124 ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); 03125 03126 if (cmdresp == DUNDI_COMMAND_ACK) 03127 ast_free(pack); 03128 return res; 03129 } 03130 return -1; 03131 }
static char* dundi_set_debug | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2269 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
02270 { 02271 switch (cmd) { 02272 case CLI_INIT: 02273 e->command = "dundi set debug {on|off}"; 02274 e->usage = 02275 "Usage: dundi set debug {on|off}\n" 02276 " Enables/Disables dumping of DUNDi packets for debugging purposes\n"; 02277 return NULL; 02278 case CLI_GENERATE: 02279 return NULL; 02280 } 02281 02282 if (a->argc != e->args) 02283 return CLI_SHOWUSAGE; 02284 02285 if (!strncasecmp(a->argv[e->args -1], "on", 2)) { 02286 dundidebug = 1; 02287 ast_cli(a->fd, "DUNDi Debugging Enabled\n"); 02288 } else { 02289 dundidebug = 0; 02290 ast_cli(a->fd, "DUNDi Debugging Disabled\n"); 02291 } 02292 return CLI_SUCCESS; 02293 }
static char* dundi_show_entityid | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2760 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
02761 { 02762 char eid_str[20]; 02763 switch (cmd) { 02764 case CLI_INIT: 02765 e->command = "dundi show entityid"; 02766 e->usage = 02767 "Usage: dundi show entityid\n" 02768 " Displays the global entityid for this host.\n"; 02769 return NULL; 02770 case CLI_GENERATE: 02771 return NULL; 02772 } 02773 if (a->argc != 3) 02774 return CLI_SHOWUSAGE; 02775 AST_LIST_LOCK(&peers); 02776 ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid); 02777 AST_LIST_UNLOCK(&peers); 02778 ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str); 02779 return CLI_SUCCESS; 02780 }
static char* dundi_show_mappings | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2814 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_mapping::dcontext, dundi_mapping::dest, dundi_flags2str(), ast_cli_args::fd, FORMAT, FORMAT2, get_mapping_weight(), dundi_mapping::lcontext, map, dundi_mapping::options, dundi_mapping::tech, tech2str(), and ast_cli_entry::usage.
02815 { 02816 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" 02817 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n" 02818 struct dundi_mapping *map; 02819 char fs[256]; 02820 char weight[8]; 02821 switch (cmd) { 02822 case CLI_INIT: 02823 e->command = "dundi show mappings"; 02824 e->usage = 02825 "Usage: dundi show mappings\n" 02826 " Lists all known DUNDi mappings.\n"; 02827 return NULL; 02828 case CLI_GENERATE: 02829 return NULL; 02830 } 02831 if (a->argc != 3) 02832 return CLI_SHOWUSAGE; 02833 AST_LIST_LOCK(&peers); 02834 ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination"); 02835 AST_LIST_TRAVERSE(&mappings, map, list) { 02836 snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map)); 02837 ast_cli(a->fd, FORMAT, map->dcontext, weight, 02838 ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 02839 dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest); 02840 } 02841 AST_LIST_UNLOCK(&peers); 02842 return CLI_SUCCESS; 02843 #undef FORMAT 02844 #undef FORMAT2 02845 }
static char* dundi_show_peer | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2561 of file pbx_dundi.c.
References dundi_peer::addr, permission::allow, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_peer_helper(), DUNDI_MODEL_INBOUND, DUNDI_MODEL_OUTBOUND, DUNDI_TIMING_HISTORY, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, dundi_peer::include, dundi_peer::inkey, ast_cli_args::line, dundi_peer::lookups, dundi_peer::lookuptimes, dundi_peer::model, model2str(), ast_cli_args::n, permission::name, dundi_peer::order, dundi_peer::outkey, dundi_peer::permit, ast_cli_args::pos, dundi_peer::registerid, ast_cli_entry::usage, and ast_cli_args::word.
02562 { 02563 struct dundi_peer *peer; 02564 struct permission *p; 02565 char *order; 02566 char eid_str[20]; 02567 int x, cnt; 02568 switch (cmd) { 02569 case CLI_INIT: 02570 e->command = "dundi show peer"; 02571 e->usage = 02572 "Usage: dundi show peer [peer]\n" 02573 " Provide a detailed description of a specifid DUNDi peer.\n"; 02574 return NULL; 02575 case CLI_GENERATE: 02576 return complete_peer_helper(a->line, a->word, a->pos, a->n, 3); 02577 } 02578 if (a->argc != 4) 02579 return CLI_SHOWUSAGE; 02580 AST_LIST_LOCK(&peers); 02581 AST_LIST_TRAVERSE(&peers, peer, list) { 02582 if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3])) 02583 break; 02584 } 02585 if (peer) { 02586 switch(peer->order) { 02587 case 0: 02588 order = "Primary"; 02589 break; 02590 case 1: 02591 order = "Secondary"; 02592 break; 02593 case 2: 02594 order = "Tertiary"; 02595 break; 02596 case 3: 02597 order = "Quartiary"; 02598 break; 02599 default: 02600 order = "Unknown"; 02601 } 02602 ast_cli(a->fd, "Peer: %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02603 ast_cli(a->fd, "Model: %s\n", model2str(peer->model)); 02604 ast_cli(a->fd, "Order: %s\n", order); 02605 ast_cli(a->fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>"); 02606 ast_cli(a->fd, "Port: %d\n", ntohs(peer->addr.sin_port)); 02607 ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no"); 02608 ast_cli(a->fd, "Reg: %s\n", peer->registerid < 0 ? "No" : "Yes"); 02609 ast_cli(a->fd, "In Key: %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey); 02610 ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey); 02611 if (!AST_LIST_EMPTY(&peer->include)) 02612 ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)"); 02613 AST_LIST_TRAVERSE(&peer->include, p, list) 02614 ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name); 02615 if (!AST_LIST_EMPTY(&peer->permit)) 02616 ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)"); 02617 AST_LIST_TRAVERSE(&peer->permit, p, list) 02618 ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name); 02619 cnt = 0; 02620 for (x = 0;x < DUNDI_TIMING_HISTORY; x++) { 02621 if (peer->lookups[x]) { 02622 if (!cnt) 02623 ast_cli(a->fd, "Last few query times:\n"); 02624 ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]); 02625 cnt++; 02626 } 02627 } 02628 if (cnt) 02629 ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms); 02630 } else 02631 ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]); 02632 AST_LIST_UNLOCK(&peers); 02633 return CLI_SUCCESS; 02634 }
static char* dundi_show_peers | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2636 of file pbx_dundi.c.
References dundi_peer::addr, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_eid_to_str(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_peer::avgms, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_peer::dynamic, dundi_peer::eid, ast_cli_args::fd, FORMAT, FORMAT2, dundi_peer::lastms, dundi_peer::maxms, dundi_peer::model, model2str(), status, and ast_cli_entry::usage.
02637 { 02638 #define FORMAT2 "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n" 02639 #define FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n" 02640 struct dundi_peer *peer; 02641 int registeredonly=0; 02642 char avgms[20]; 02643 char eid_str[20]; 02644 int online_peers = 0; 02645 int offline_peers = 0; 02646 int unmonitored_peers = 0; 02647 int total_peers = 0; 02648 switch (cmd) { 02649 case CLI_INIT: 02650 e->command = "dundi show peers [registered|include|exclude|begin]"; 02651 e->usage = 02652 "Usage: dundi show peers [registered|include|exclude|begin]\n" 02653 " Lists all known DUNDi peers.\n" 02654 " If 'registered' is present, only registered peers are shown.\n"; 02655 return NULL; 02656 case CLI_GENERATE: 02657 return NULL; 02658 } 02659 02660 if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5)) 02661 return CLI_SHOWUSAGE; 02662 if ((a->argc == 4)) { 02663 if (!strcasecmp(a->argv[3], "registered")) { 02664 registeredonly = 1; 02665 } else 02666 return CLI_SHOWUSAGE; 02667 } 02668 AST_LIST_LOCK(&peers); 02669 ast_cli(a->fd, FORMAT2, "EID", "Host", "Port", "Model", "AvgTime", "Status"); 02670 AST_LIST_TRAVERSE(&peers, peer, list) { 02671 char status[20]; 02672 int print_line = -1; 02673 char srch[2000]; 02674 total_peers++; 02675 if (registeredonly && !peer->addr.sin_addr.s_addr) 02676 continue; 02677 if (peer->maxms) { 02678 if (peer->lastms < 0) { 02679 strcpy(status, "UNREACHABLE"); 02680 offline_peers++; 02681 } 02682 else if (peer->lastms > peer->maxms) { 02683 snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms); 02684 offline_peers++; 02685 } 02686 else if (peer->lastms) { 02687 snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms); 02688 online_peers++; 02689 } 02690 else { 02691 strcpy(status, "UNKNOWN"); 02692 offline_peers++; 02693 } 02694 } else { 02695 strcpy(status, "Unmonitored"); 02696 unmonitored_peers++; 02697 } 02698 if (peer->avgms) 02699 snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms); 02700 else 02701 strcpy(avgms, "Unavail"); 02702 snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 02703 peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", 02704 peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status); 02705 02706 if (a->argc == 5) { 02707 if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) { 02708 print_line = -1; 02709 } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) { 02710 print_line = 1; 02711 } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) { 02712 print_line = -1; 02713 } else { 02714 print_line = 0; 02715 } 02716 } 02717 02718 if (print_line) { 02719 ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 02720 peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", 02721 peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status); 02722 } 02723 } 02724 ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers); 02725 AST_LIST_UNLOCK(&peers); 02726 return CLI_SUCCESS; 02727 #undef FORMAT 02728 #undef FORMAT2 02729 }
static char* dundi_show_precache | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2847 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_precache_queue::context, dundi_precache_queue::expiration, ast_cli_args::fd, FORMAT, FORMAT2, dundi_precache_queue::number, and ast_cli_entry::usage.
02848 { 02849 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n" 02850 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n" 02851 struct dundi_precache_queue *qe; 02852 int h,m,s; 02853 time_t now; 02854 switch (cmd) { 02855 case CLI_INIT: 02856 e->command = "dundi show precache"; 02857 e->usage = 02858 "Usage: dundi show precache\n" 02859 " Lists all known DUNDi scheduled precache updates.\n"; 02860 return NULL; 02861 case CLI_GENERATE: 02862 return NULL; 02863 } 02864 if (a->argc != 3) 02865 return CLI_SHOWUSAGE; 02866 time(&now); 02867 ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration"); 02868 AST_LIST_LOCK(&pcq); 02869 AST_LIST_TRAVERSE(&pcq, qe, list) { 02870 s = qe->expiration - now; 02871 h = s / 3600; 02872 s = s % 3600; 02873 m = s / 60; 02874 s = s % 60; 02875 ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s); 02876 } 02877 AST_LIST_UNLOCK(&pcq); 02878 02879 return CLI_SUCCESS; 02880 #undef FORMAT 02881 #undef FORMAT2 02882 }
static char* dundi_show_requests | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2782 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli(), ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_request::dcontext, dundi_eid_zero(), ast_cli_args::fd, FORMAT, FORMAT2, dundi_request::maxcount, dundi_request::number, dundi_request::respcount, dundi_request::root_eid, and ast_cli_entry::usage.
02783 { 02784 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" 02785 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n" 02786 struct dundi_request *req; 02787 char eidstr[20]; 02788 switch (cmd) { 02789 case CLI_INIT: 02790 e->command = "dundi show requests"; 02791 e->usage = 02792 "Usage: dundi show requests\n" 02793 " Lists all known pending DUNDi requests.\n"; 02794 return NULL; 02795 case CLI_GENERATE: 02796 return NULL; 02797 } 02798 if (a->argc != 3) 02799 return CLI_SHOWUSAGE; 02800 AST_LIST_LOCK(&peers); 02801 ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp"); 02802 AST_LIST_TRAVERSE(&requests, req, list) { 02803 ast_cli(a->fd, FORMAT, req->number, req->dcontext, 02804 dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount); 02805 } 02806 AST_LIST_UNLOCK(&peers); 02807 return CLI_SUCCESS; 02808 #undef FORMAT 02809 #undef FORMAT2 02810 }
static char* dundi_show_trans | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2731 of file pbx_dundi.c.
References dundi_transaction::addr, ast_cli_args::argc, dundi_transaction::aseqno, ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, dundi_transaction::dtrans, ast_cli_args::fd, FORMAT, FORMAT2, dundi_transaction::iseqno, dundi_transaction::oseqno, dundi_transaction::strans, and ast_cli_entry::usage.
02732 { 02733 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" 02734 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" 02735 struct dundi_transaction *trans; 02736 switch (cmd) { 02737 case CLI_INIT: 02738 e->command = "dundi show trans"; 02739 e->usage = 02740 "Usage: dundi show trans\n" 02741 " Lists all known DUNDi transactions.\n"; 02742 return NULL; 02743 case CLI_GENERATE: 02744 return NULL; 02745 } 02746 if (a->argc != 3) 02747 return CLI_SHOWUSAGE; 02748 AST_LIST_LOCK(&peers); 02749 ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack"); 02750 AST_LIST_TRAVERSE(&alltrans, trans, all) { 02751 ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 02752 ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); 02753 } 02754 AST_LIST_UNLOCK(&peers); 02755 return CLI_SUCCESS; 02756 #undef FORMAT 02757 #undef FORMAT2 02758 }
static char* dundi_store_history | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2295 of file pbx_dundi.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
02296 { 02297 switch (cmd) { 02298 case CLI_INIT: 02299 e->command = "dundi store history {on|off}"; 02300 e->usage = 02301 "Usage: dundi store history {on|off}\n" 02302 " Enables/Disables storing of DUNDi requests and times for debugging\n" 02303 "purposes\n"; 02304 return NULL; 02305 case CLI_GENERATE: 02306 return NULL; 02307 } 02308 02309 if (a->argc != e->args) 02310 return CLI_SHOWUSAGE; 02311 02312 if (!strncasecmp(a->argv[e->args -1], "on", 2)) { 02313 global_storehistory = 1; 02314 ast_cli(a->fd, "DUNDi History Storage Enabled\n"); 02315 } else { 02316 global_storehistory = 0; 02317 ast_cli(a->fd, "DUNDi History Storage Disabled\n"); 02318 } 02319 return CLI_SUCCESS; 02320 }
static int dundi_xmit | ( | struct dundi_packet * | pack | ) | [static] |
Definition at line 2931 of file pbx_dundi.c.
References dundi_transaction::addr, ast_inet_ntoa(), ast_log(), dundi_packet::data, dundi_packet::datalen, dundi_showframe(), errno, dundi_packet::h, LOG_WARNING, and dundi_packet::parent.
Referenced by dundi_reject(), dundi_rexmit(), and dundi_send().
02932 { 02933 int res; 02934 if (dundidebug) 02935 dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr)); 02936 res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr)); 02937 if (res < 0) { 02938 ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 02939 ast_inet_ntoa(pack->parent->addr.sin_addr), 02940 ntohs(pack->parent->addr.sin_port), strerror(errno)); 02941 } 02942 if (res > 0) 02943 res = 0; 02944 return res; 02945 }
static int dundifunc_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | num, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3890 of file pbx_dundi.c.
References args, AST_APP_ARG, ast_app_parse_options(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, DUNDI_FLAG_EXISTS, dundi_lookup(), dundi_query_opts, LOG_WARNING, OPT_BYPASS_CACHE, parse(), and sort_results().
03891 { 03892 int results; 03893 int x; 03894 struct dundi_result dr[MAX_RESULTS]; 03895 AST_DECLARE_APP_ARGS(args, 03896 AST_APP_ARG(number); 03897 AST_APP_ARG(context); 03898 AST_APP_ARG(options); 03899 ); 03900 char *parse; 03901 struct ast_flags opts = { 0, }; 03902 03903 buf[0] = '\0'; 03904 03905 if (ast_strlen_zero(num)) { 03906 ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n"); 03907 return -1; 03908 } 03909 03910 parse = ast_strdupa(num); 03911 03912 AST_STANDARD_APP_ARGS(args, parse); 03913 03914 if (!ast_strlen_zero(args.options)) { 03915 ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options); 03916 } 03917 if (ast_strlen_zero(args.context)) { 03918 args.context = "e164"; 03919 } 03920 03921 results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE)); 03922 if (results > 0) { 03923 sort_results(dr, results); 03924 for (x = 0; x < results; x++) { 03925 if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) { 03926 snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest); 03927 break; 03928 } 03929 } 03930 } 03931 03932 return 0; 03933 }
static int encrypt_memcpy | ( | unsigned char * | dst, | |
unsigned char * | src, | |||
int | len, | |||
unsigned char * | iv, | |||
ast_aes_encrypt_key * | ecx | |||
) | [static] |
Definition at line 1351 of file pbx_dundi.c.
References ast_aes_encrypt().
Referenced by dundi_encrypt().
01352 { 01353 unsigned char curblock[16]; 01354 int x; 01355 memcpy(curblock, iv, sizeof(curblock)); 01356 while(len > 0) { 01357 for (x=0;x<16;x++) 01358 curblock[x] ^= src[x]; 01359 ast_aes_encrypt(curblock, dst, ecx); 01360 memcpy(curblock, dst, sizeof(curblock)); 01361 dst += 16; 01362 src += 16; 01363 len -= 16; 01364 } 01365 return 0; 01366 }
static struct dundi_peer* find_peer | ( | dundi_eid * | eid | ) | [static, read] |
Definition at line 504 of file pbx_dundi.c.
References any_peer, ast_eid_cmp(), AST_LIST_TRAVERSE, and dundi_peer::eid.
Referenced by dundi_encrypt(), handle_command_response(), and set_config().
00505 { 00506 struct dundi_peer *cur = NULL; 00507 00508 if (!eid) 00509 eid = &empty_eid; 00510 00511 AST_LIST_TRAVERSE(&peers, cur, list) { 00512 if (!ast_eid_cmp(&cur->eid,eid)) 00513 break; 00514 } 00515 00516 if (!cur && any_peer) 00517 cur = any_peer; 00518 00519 return cur; 00520 }
static struct dundi_transaction* find_transaction | ( | struct dundi_hdr * | hdr, | |
struct sockaddr_in * | sin | |||
) | [static, read] |
Definition at line 402 of file pbx_dundi.c.
References dundi_transaction::addr, AST_LIST_TRAVERSE, 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(), dundi_hdr::strans, and dundi_transaction::strans.
Referenced by handle_frame().
00403 { 00404 struct dundi_transaction *trans; 00405 00406 /* Look for an exact match first */ 00407 AST_LIST_TRAVERSE(&alltrans, trans, all) { 00408 if (!inaddrcmp(&trans->addr, sin) && 00409 ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || 00410 ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { 00411 if (hdr->strans) 00412 trans->dtrans = ntohs(hdr->strans) & 32767; 00413 return trans; 00414 } 00415 } 00416 00417 switch(hdr->cmdresp & 0x7f) { 00418 case DUNDI_COMMAND_DPDISCOVER: 00419 case DUNDI_COMMAND_EIDQUERY: 00420 case DUNDI_COMMAND_PRECACHERQ: 00421 case DUNDI_COMMAND_REGREQ: 00422 case DUNDI_COMMAND_NULL: 00423 case DUNDI_COMMAND_ENCRYPT: 00424 if (!hdr->strans) 00425 break; 00426 /* Create new transaction */ 00427 if (!(trans = create_transaction(NULL))) 00428 break; 00429 memcpy(&trans->addr, sin, sizeof(trans->addr)); 00430 trans->dtrans = ntohs(hdr->strans) & 32767; 00431 default: 00432 break; 00433 } 00434 00435 return trans; 00436 }
static int get_mapping_weight | ( | struct dundi_mapping * | map | ) | [static] |
Definition at line 548 of file pbx_dundi.c.
References dundi_mapping::_weight, MAX_WEIGHT, pbx_substitute_variables_helper(), and dundi_mapping::weightstr.
Referenced by dundi_lookup_local(), and dundi_show_mappings().
00549 { 00550 char buf[32]; 00551 00552 buf[0] = 0; 00553 if (map->weightstr) { 00554 pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1); 00555 if (sscanf(buf, "%30d", &map->_weight) != 1) 00556 map->_weight = MAX_WEIGHT; 00557 } 00558 00559 return map->_weight; 00560 }
static int get_trans_id | ( | void | ) | [static] |
Definition at line 469 of file pbx_dundi.c.
References AST_LIST_TRAVERSE, ast_random(), and dundi_transaction::strans.
Referenced by create_transaction(), and reset_transaction().
00470 { 00471 struct dundi_transaction *t; 00472 int stid = (ast_random() % 32766) + 1; 00473 int tid = stid; 00474 00475 do { 00476 AST_LIST_TRAVERSE(&alltrans, t, all) { 00477 if (t->strans == tid) 00478 break; 00479 } 00480 if (!t) 00481 return tid; 00482 tid = (tid % 32766) + 1; 00483 } while (tid != stid); 00484 00485 return 0; 00486 }
static int handle_command_response | ( | struct dundi_transaction * | trans, | |
struct dundi_hdr * | hdr, | |||
int | datalen, | |||
int | encrypted | |||
) | [static] |
Definition at line 1553 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_alloca, ast_calloc, ast_clear_flag, ast_clear_flag_nonstd, ast_copy_string(), ast_db_put(), ast_debug, ast_eid_cmp(), ast_eid_to_str(), ast_free, 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_verb, cache_save(), cache_save_hint(), dundi_ies::called_context, dundi_ies::called_number, dundi_ies::cause, check_key(), dundi_hdr::cmdresp, dundi_entity_info::country, dundi_hint::data, dundi_answer::data, dundi_request::dcontext, dundi_transaction::dcx, deep_copy_peer(), dundi_request::dei, dundi_result::dest, do_register_expire(), dundi_request::dr, 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_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_peer::dynamic, dundi_transaction::ecx, dundi_answer::eid, dundi_result::eid, dundi_peer::eid, dundi_result::eid_str, dundi_ies::eidcount, dundi_ies::eids, dundi_entity_info::email, dundi_ies::encblock, dundi_encblock::encdata, dundi_ies::enclen, dundi_ies::encsharedkey, dundi_ies::encsig, dundi_request::expiration, dundi_result::expiration, dundi_ies::expiration, dundi_hint_metadata::exten, find_peer(), FLAG_ENCRYPT, FLAG_SENDFULLKEY, dundi_answer::flags, dundi_result::flags, has_permission(), dundi_ies::hint, dundi_request::hmd, dundi_hdr::ies, inaddrcmp(), dundi_peer::include, dundi_peer::inkey, dundi_entity_info::ipaddr, dundi_transaction::iseqno, dundi_encblock::iv, dundi_ies::keycrc32, dundi_transaction::lasttrans, dundi_entity_info::locality, LOG_NOTICE, LOG_WARNING, MAX_PACKET_SIZE, dundi_request::maxcount, dundi_peer::model, dundi_request::number, dundi_entity_info::org, dundi_entity_info::orgunit, dundi_transaction::oseqno, dundi_hdr::oseqno, dundi_transaction::parent, dundi_peer::pcmodel, dundi_peer::permit, dundi_entity_info::phone, dundi_ie_data::pos, 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(), dundi_request::query_eid, dundi_peer::registerexpire, reset_transaction(), dundi_request::respcount, dundi_peer::sentfullkey, dundi_entity_info::stateprov, dundi_result::tech, tech2str(), dundi_result::techint, dundi_peer::them_dcx, dundi_peer::them_ecx, dundi_transaction::them_eid, dundi_peer::txenckey, dundi_peer::us_eid, dundi_transaction::us_eid, dundi_answer::weight, and dundi_result::weight.
Referenced by handle_frame().
01554 { 01555 /* Handle canonical command / response */ 01556 int final = hdr->cmdresp & 0x80; 01557 int cmd = hdr->cmdresp & 0x7f; 01558 int x,y,z; 01559 int resp; 01560 int res; 01561 int authpass=0; 01562 unsigned char *bufcpy; 01563 #ifdef LOW_MEMORY 01564 struct dundi_ie_data *ied = ast_calloc(1, sizeof(*ied)); 01565 #else 01566 struct dundi_ie_data _ied = { 01567 .pos = 0, 01568 }; 01569 struct dundi_ie_data *ied = &_ied; 01570 #endif 01571 struct dundi_ies ies = { 01572 .eidcount = 0, 01573 }; 01574 struct dundi_peer *peer = NULL; 01575 char eid_str[20]; 01576 char eid_str2[20]; 01577 int retval = -1; 01578 01579 if (!ied) { 01580 return -1; 01581 } 01582 01583 if (datalen) { 01584 bufcpy = ast_alloca(datalen); 01585 /* Make a copy for parsing */ 01586 memcpy(bufcpy, hdr->ies, datalen); 01587 ast_debug(1, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : ""); 01588 if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) { 01589 ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n"); 01590 goto return_cleanup; 01591 } 01592 } 01593 switch(cmd) { 01594 case DUNDI_COMMAND_DPDISCOVER: 01595 case DUNDI_COMMAND_EIDQUERY: 01596 case DUNDI_COMMAND_PRECACHERQ: 01597 if (cmd == DUNDI_COMMAND_EIDQUERY) 01598 resp = DUNDI_COMMAND_EIDRESPONSE; 01599 else if (cmd == DUNDI_COMMAND_PRECACHERQ) 01600 resp = DUNDI_COMMAND_PRECACHERP; 01601 else 01602 resp = DUNDI_COMMAND_DPRESPONSE; 01603 /* A dialplan or entity discover -- qualify by highest level entity */ 01604 peer = find_peer(ies.eids[0]); 01605 if (!peer) { 01606 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); 01607 dundi_send(trans, resp, 0, 1, ied); 01608 } else { 01609 int hasauth = 0; 01610 trans->us_eid = peer->us_eid; 01611 if (strlen(peer->inkey)) { 01612 hasauth = encrypted; 01613 } else 01614 hasauth = 1; 01615 if (hasauth) { 01616 /* Okay we're authentiated and all, now we check if they're authorized */ 01617 if (!ies.called_context) 01618 ies.called_context = "e164"; 01619 if (cmd == DUNDI_COMMAND_EIDQUERY) { 01620 res = dundi_answer_entity(trans, &ies, ies.called_context); 01621 } else { 01622 if (ast_strlen_zero(ies.called_number)) { 01623 /* They're not permitted to access that context */ 01624 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity"); 01625 dundi_send(trans, resp, 0, 1, ied); 01626 } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) && 01627 (peer->model & DUNDI_MODEL_INBOUND) && 01628 has_permission(&peer->permit, ies.called_context)) { 01629 res = dundi_answer_query(trans, &ies, ies.called_context); 01630 if (res < 0) { 01631 /* There is no such dundi context */ 01632 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); 01633 dundi_send(trans, resp, 0, 1, ied); 01634 } 01635 } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) && 01636 (peer->pcmodel & DUNDI_MODEL_INBOUND) && 01637 has_permission(&peer->include, ies.called_context)) { 01638 res = dundi_prop_precache(trans, &ies, ies.called_context); 01639 if (res < 0) { 01640 /* There is no such dundi context */ 01641 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); 01642 dundi_send(trans, resp, 0, 1, ied); 01643 } 01644 } else { 01645 /* They're not permitted to access that context */ 01646 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied"); 01647 dundi_send(trans, resp, 0, 1, ied); 01648 } 01649 } 01650 } else { 01651 /* They're not permitted to access that context */ 01652 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted"); 01653 dundi_send(trans, resp, 0, 1, ied); 01654 } 01655 } 01656 break; 01657 case DUNDI_COMMAND_REGREQ: 01658 /* A register request -- should only have one entity */ 01659 peer = find_peer(ies.eids[0]); 01660 01661 /* if the peer is not found and we have a valid 'any_peer' setting */ 01662 if (any_peer && peer == any_peer) { 01663 /* copy any_peer into a new peer object */ 01664 peer = ast_calloc(1, sizeof(*peer)); 01665 if (peer) { 01666 deep_copy_peer(peer, any_peer); 01667 01668 /* set EID to remote EID */ 01669 peer->eid = *ies.eids[0]; 01670 01671 AST_LIST_LOCK(&peers); 01672 AST_LIST_INSERT_HEAD(&peers, peer, list); 01673 AST_LIST_UNLOCK(&peers); 01674 } 01675 } 01676 01677 if (!peer || !peer->dynamic) { 01678 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); 01679 dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); 01680 } else { 01681 int hasauth = 0; 01682 trans->us_eid = peer->us_eid; 01683 if (!ast_strlen_zero(peer->inkey)) { 01684 hasauth = encrypted; 01685 } else 01686 hasauth = 1; 01687 if (hasauth) { 01688 int expire = default_expiration; 01689 char data[256]; 01690 int needqual = 0; 01691 AST_SCHED_DEL(sched, peer->registerexpire); 01692 peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); 01693 snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr), 01694 ntohs(trans->addr.sin_port), expire); 01695 ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data); 01696 if (inaddrcmp(&peer->addr, &trans->addr)) { 01697 ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n", 01698 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 01699 ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port)); 01700 needqual = 1; 01701 } 01702 01703 memcpy(&peer->addr, &trans->addr, sizeof(peer->addr)); 01704 dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration); 01705 dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); 01706 if (needqual) 01707 qualify_peer(peer, 1); 01708 } 01709 } 01710 break; 01711 case DUNDI_COMMAND_DPRESPONSE: 01712 /* A dialplan response, lets see what we got... */ 01713 if (ies.cause < 1) { 01714 /* Success of some sort */ 01715 ast_debug(1, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount); 01716 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01717 authpass = encrypted; 01718 } else 01719 authpass = 1; 01720 if (authpass) { 01721 /* Pass back up answers */ 01722 if (trans->parent && trans->parent->dr) { 01723 y = trans->parent->respcount; 01724 for (x=0;x<ies.anscount;x++) { 01725 if (trans->parent->respcount < trans->parent->maxcount) { 01726 /* Make sure it's not already there */ 01727 for (z=0;z<trans->parent->respcount;z++) { 01728 if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) && 01729 !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data)) 01730 break; 01731 } 01732 if (z == trans->parent->respcount) { 01733 /* Copy into parent responses */ 01734 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags); 01735 trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol; 01736 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight); 01737 trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid; 01738 if (ies.expiration > 0) 01739 trans->parent->dr[trans->parent->respcount].expiration = ies.expiration; 01740 else 01741 trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; 01742 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 01743 sizeof(trans->parent->dr[trans->parent->respcount].eid_str), 01744 &ies.answers[x]->eid); 01745 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data, 01746 sizeof(trans->parent->dr[trans->parent->respcount].dest)); 01747 ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol), 01748 sizeof(trans->parent->dr[trans->parent->respcount].tech)); 01749 trans->parent->respcount++; 01750 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 01751 } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) { 01752 /* Update weight if appropriate */ 01753 trans->parent->dr[z].weight = ies.answers[x]->weight; 01754 } 01755 } else 01756 ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n", 01757 trans->parent->number, trans->parent->dcontext); 01758 } 01759 /* Save all the results (if any) we had. Even if no results, still cache lookup. Let 01760 the cache know if this request was unaffected by our entity list. */ 01761 cache_save(&trans->them_eid, trans->parent, y, 01762 ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0); 01763 if (ies.hint) { 01764 cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration); 01765 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) 01766 ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); 01767 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) { 01768 if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) { 01769 ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data, 01770 sizeof(trans->parent->hmd->exten)); 01771 } 01772 } else { 01773 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 01774 } 01775 } 01776 if (ies.expiration > 0) { 01777 if (trans->parent->expiration > ies.expiration) { 01778 trans->parent->expiration = ies.expiration; 01779 } 01780 } 01781 } 01782 /* Close connection if not final */ 01783 if (!final) 01784 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01785 } 01786 01787 } else { 01788 /* Auth failure, check for data */ 01789 if (!final) { 01790 /* Cancel if they didn't already */ 01791 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01792 } 01793 } 01794 break; 01795 case DUNDI_COMMAND_EIDRESPONSE: 01796 /* A dialplan response, lets see what we got... */ 01797 if (ies.cause < 1) { 01798 /* Success of some sort */ 01799 ast_debug(1, "Looks like success of some sort (%d)\n", ies.cause); 01800 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01801 authpass = encrypted; 01802 } else 01803 authpass = 1; 01804 if (authpass) { 01805 /* Pass back up answers */ 01806 if (trans->parent && trans->parent->dei && ies.q_org) { 01807 if (!trans->parent->respcount) { 01808 trans->parent->respcount++; 01809 if (ies.q_dept) 01810 ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit)); 01811 if (ies.q_org) 01812 ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org)); 01813 if (ies.q_locality) 01814 ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality)); 01815 if (ies.q_stateprov) 01816 ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov)); 01817 if (ies.q_country) 01818 ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country)); 01819 if (ies.q_email) 01820 ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email)); 01821 if (ies.q_phone) 01822 ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone)); 01823 if (ies.q_ipaddr) 01824 ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr)); 01825 if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) { 01826 /* If it's them, update our address */ 01827 ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr)); 01828 } 01829 } 01830 if (ies.hint) { 01831 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) 01832 ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); 01833 } 01834 } 01835 /* Close connection if not final */ 01836 if (!final) 01837 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01838 } 01839 01840 } else { 01841 /* Auth failure, check for data */ 01842 if (!final) { 01843 /* Cancel if they didn't already */ 01844 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01845 } 01846 } 01847 break; 01848 case DUNDI_COMMAND_REGRESPONSE: 01849 /* A dialplan response, lets see what we got... */ 01850 if (ies.cause < 1) { 01851 int hasauth; 01852 /* Success of some sort */ 01853 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01854 hasauth = encrypted; 01855 } else 01856 hasauth = 1; 01857 01858 if (!hasauth) { 01859 ast_log(LOG_NOTICE, "Reponse to register not authorized!\n"); 01860 if (!final) { 01861 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer"); 01862 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, ied); 01863 } 01864 } else { 01865 ast_debug(1, "Yay, we've registered as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid), 01866 ast_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid)); 01867 /* Close connection if not final */ 01868 if (!final) 01869 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01870 } 01871 } else { 01872 /* Auth failure, cancel if they didn't for some reason */ 01873 if (!final) { 01874 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01875 } 01876 } 01877 break; 01878 case DUNDI_COMMAND_INVALID: 01879 case DUNDI_COMMAND_NULL: 01880 case DUNDI_COMMAND_PRECACHERP: 01881 /* Do nothing special */ 01882 if (!final) 01883 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01884 break; 01885 case DUNDI_COMMAND_ENCREJ: 01886 if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || AST_LIST_EMPTY(&trans->lasttrans) || !(peer = find_peer(&trans->them_eid))) { 01887 /* No really, it's over at this point */ 01888 if (!final) 01889 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01890 } else { 01891 /* Send with full key */ 01892 ast_set_flag(trans, FLAG_SENDFULLKEY); 01893 if (final) { 01894 /* Ooops, we got a final message, start by sending ACK... */ 01895 dundi_ack(trans, hdr->cmdresp & 0x80); 01896 trans->aseqno = trans->iseqno; 01897 /* Now, we gotta create a new transaction */ 01898 if (!reset_transaction(trans)) { 01899 /* Make sure handle_frame doesn't destroy us */ 01900 hdr->cmdresp &= 0x7f; 01901 /* Parse the message we transmitted */ 01902 memset(&ies, 0, sizeof(ies)); 01903 dundi_parse_ies(&ies, (AST_LIST_FIRST(&trans->lasttrans))->h->ies, (AST_LIST_FIRST(&trans->lasttrans))->datalen - sizeof(struct dundi_hdr)); 01904 /* Reconstruct outgoing encrypted packet */ 01905 memset(ied, 0, sizeof(*ied)); 01906 dundi_ie_append_eid(ied, DUNDI_IE_EID, &trans->us_eid); 01907 dundi_ie_append_raw(ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); 01908 dundi_ie_append_raw(ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); 01909 if (ies.encblock) 01910 dundi_ie_append_encdata(ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen); 01911 dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, (AST_LIST_FIRST(&trans->lasttrans))->h->cmdresp & 0x80, ied); 01912 peer->sentfullkey = 1; 01913 } 01914 } 01915 } 01916 break; 01917 case DUNDI_COMMAND_ENCRYPT: 01918 if (!encrypted) { 01919 /* No nested encryption! */ 01920 if ((trans->iseqno == 1) && !trans->oseqno) { 01921 if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) || 01922 ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) || 01923 (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) { 01924 if (!final) { 01925 dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); 01926 } 01927 break; 01928 } 01929 apply_peer(trans, peer); 01930 /* Key passed, use new contexts for this session */ 01931 trans->ecx = peer->them_ecx; 01932 trans->dcx = peer->them_dcx; 01933 } 01934 if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) { 01935 struct dundi_hdr *dhdr; 01936 unsigned char decoded[MAX_PACKET_SIZE]; 01937 int ddatalen; 01938 ddatalen = sizeof(decoded); 01939 dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen); 01940 if (dhdr) { 01941 /* Handle decrypted response */ 01942 if (dundidebug) 01943 dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr)); 01944 handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1); 01945 /* Carry back final flag */ 01946 hdr->cmdresp |= dhdr->cmdresp & 0x80; 01947 break; 01948 } else { 01949 ast_debug(1, "Ouch, decrypt failed :(\n"); 01950 } 01951 } 01952 } 01953 if (!final) { 01954 /* Turn off encryption */ 01955 ast_clear_flag(trans, FLAG_ENCRYPT); 01956 dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); 01957 } 01958 break; 01959 default: 01960 /* Send unknown command if we don't know it, with final flag IFF it's the 01961 first command in the dialog and only if we haven't received final notification */ 01962 if (!final) { 01963 dundi_ie_append_byte(ied, DUNDI_IE_UNKNOWN, cmd); 01964 dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, ied); 01965 } 01966 } 01967 01968 retval = 0; 01969 01970 return_cleanup: 01971 #ifdef LOW_MEMORY 01972 ast_free(ied); 01973 #endif 01974 return retval; 01975 }
static int handle_frame | ( | struct dundi_hdr * | h, | |
struct sockaddr_in * | sin, | |||
int | datalen | |||
) | [static] |
Definition at line 2010 of file pbx_dundi.c.
References ack_trans(), dundi_transaction::aseqno, ast_debug, ast_test_flag, dundi_hdr::cmdresp, destroy_packets(), destroy_trans(), dundi_ack(), DUNDI_COMMAND_ACK, dundi_reject(), find_transaction(), FLAG_FINAL, handle_command_response(), dundi_hdr::iseqno, dundi_transaction::iseqno, dundi_transaction::lasttrans, dundi_transaction::oiseqno, and dundi_hdr::oseqno.
Referenced by socket_read().
02011 { 02012 struct dundi_transaction *trans; 02013 trans = find_transaction(h, sin); 02014 if (!trans) { 02015 dundi_reject(h, sin); 02016 return 0; 02017 } 02018 /* Got a transaction, see where this header fits in */ 02019 if (h->oseqno == trans->iseqno) { 02020 /* Just what we were looking for... Anything but ack increments iseqno */ 02021 if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) { 02022 /* If final, we're done */ 02023 destroy_trans(trans, 0); 02024 return 0; 02025 } 02026 if (h->cmdresp != DUNDI_COMMAND_ACK) { 02027 trans->oiseqno = trans->iseqno; 02028 trans->iseqno++; 02029 handle_command_response(trans, h, datalen, 0); 02030 } 02031 if (trans->aseqno != trans->iseqno) { 02032 dundi_ack(trans, h->cmdresp & 0x80); 02033 trans->aseqno = trans->iseqno; 02034 } 02035 /* Delete any saved last transmissions */ 02036 destroy_packets(&trans->lasttrans); 02037 if (h->cmdresp & 0x80) { 02038 /* Final -- destroy now */ 02039 destroy_trans(trans, 0); 02040 } 02041 } else if (h->oseqno == trans->oiseqno) { 02042 /* Last incoming sequence number -- send ACK without processing */ 02043 dundi_ack(trans, 0); 02044 } else { 02045 /* Out of window -- simply drop */ 02046 ast_debug(1, "Dropping packet out of window!\n"); 02047 } 02048 return 0; 02049 }
static int has_permission | ( | struct permissionlist * | permlist, | |
char * | cont | |||
) | [static] |
Definition at line 358 of file pbx_dundi.c.
References permission::allow, AST_LIST_TRAVERSE, and permission::name.
Referenced by build_transactions(), dundi_ie_append_eid_appropriately(), handle_command_response(), and optimize_transactions().
00359 { 00360 struct permission *perm; 00361 int res = 0; 00362 00363 AST_LIST_TRAVERSE(permlist, perm, list) { 00364 if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont)) 00365 res = perm->allow; 00366 } 00367 00368 return res; 00369 }
static int load_module | ( | void | ) | [static] |
Definition at line 4809 of file pbx_dundi.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_inet_ntoa(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_netsock_set_qos(), ast_register_switch(), ast_verb, dundi_debug_output(), dundi_error_output(), DUNDI_PORT, dundi_set_error(), dundi_set_output(), errno, io_context_create(), LOG_ERROR, sched_context_create(), set_config(), and start_network_thread().
04810 { 04811 struct sockaddr_in sin; 04812 04813 dundi_set_output(dundi_debug_output); 04814 dundi_set_error(dundi_error_output); 04815 04816 sin.sin_family = AF_INET; 04817 sin.sin_port = htons(DUNDI_PORT); 04818 sin.sin_addr.s_addr = INADDR_ANY; 04819 04820 /* Make a UDP socket */ 04821 io = io_context_create(); 04822 sched = sched_context_create(); 04823 04824 if (!io || !sched) 04825 return AST_MODULE_LOAD_DECLINE; 04826 04827 if (set_config("dundi.conf", &sin, 0)) 04828 return AST_MODULE_LOAD_DECLINE; 04829 04830 netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 04831 04832 if (netsocket < 0) { 04833 ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); 04834 return AST_MODULE_LOAD_DECLINE; 04835 } 04836 if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) { 04837 ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", 04838 ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno)); 04839 return AST_MODULE_LOAD_DECLINE; 04840 } 04841 04842 ast_netsock_set_qos(netsocket, tos, 0, "DUNDi"); 04843 04844 if (start_network_thread()) { 04845 ast_log(LOG_ERROR, "Unable to start network thread\n"); 04846 close(netsocket); 04847 return AST_MODULE_LOAD_DECLINE; 04848 } 04849 04850 ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); 04851 if (ast_register_switch(&dundi_switch)) 04852 ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); 04853 ast_custom_function_register(&dundi_function); 04854 ast_custom_function_register(&dundi_query_function); 04855 ast_custom_function_register(&dundi_result_function); 04856 04857 ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); 04858 04859 return AST_MODULE_LOAD_SUCCESS; 04860 }
static void load_password | ( | void | ) | [static] |
Definition at line 2107 of file pbx_dundi.c.
References ast_copy_string(), ast_db_get(), ast_get_time_t(), build_secret(), DUNDI_SECRET_TIME, last, and save_secret().
Referenced by set_config().
02108 { 02109 char *current=NULL; 02110 char *last=NULL; 02111 char tmp[256]; 02112 time_t expired; 02113 02114 ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp)); 02115 if (!ast_get_time_t(tmp, &expired, 0, NULL)) { 02116 ast_db_get(secretpath, "secret", tmp, sizeof(tmp)); 02117 current = strchr(tmp, ';'); 02118 if (!current) 02119 current = tmp; 02120 else { 02121 *current = '\0'; 02122 current++; 02123 }; 02124 if ((time(NULL) - expired) < 0) { 02125 if ((expired - time(NULL)) > DUNDI_SECRET_TIME) 02126 expired = time(NULL) + DUNDI_SECRET_TIME; 02127 } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) { 02128 last = current; 02129 current = NULL; 02130 } else { 02131 last = NULL; 02132 current = NULL; 02133 } 02134 } 02135 if (current) { 02136 /* Current key is still valid, just setup rotatation properly */ 02137 ast_copy_string(cursecret, current, sizeof(cursecret)); 02138 rotatetime = expired; 02139 } else { 02140 /* Current key is out of date, rotate or eliminate all together */ 02141 build_secret(cursecret, sizeof(cursecret)); 02142 save_secret(cursecret, last); 02143 } 02144 }
static void mark_mappings | ( | void | ) | [static] |
Definition at line 4116 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_mapping::dead, and map.
Referenced by set_config(), and unload_module().
04117 { 04118 struct dundi_mapping *map; 04119 04120 AST_LIST_LOCK(&peers); 04121 AST_LIST_TRAVERSE(&mappings, map, list) { 04122 map->dead = 1; 04123 } 04124 AST_LIST_UNLOCK(&peers); 04125 }
static void mark_peers | ( | void | ) | [static] |
Definition at line 4106 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and dundi_peer::dead.
Referenced by set_config(), and unload_module().
04107 { 04108 struct dundi_peer *peer; 04109 AST_LIST_LOCK(&peers); 04110 AST_LIST_TRAVERSE(&peers, peer, list) { 04111 peer->dead = 1; 04112 } 04113 AST_LIST_UNLOCK(&peers); 04114 }
static char* model2str | ( | int | model | ) | [static] |
Definition at line 2367 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().
02368 { 02369 switch(model) { 02370 case DUNDI_MODEL_INBOUND: 02371 return "Inbound"; 02372 case DUNDI_MODEL_OUTBOUND: 02373 return "Outbound"; 02374 case DUNDI_MODEL_SYMMETRIC: 02375 return "Symmetric"; 02376 default: 02377 return "Unknown"; 02378 } 02379 }
static void* network_thread | ( | void * | ignore | ) | [static] |
Definition at line 2163 of file pbx_dundi.c.
References ast_io_add(), AST_IO_IN, ast_io_remove(), ast_io_wait(), AST_LIST_LOCK, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_sched_runq(), ast_sched_wait(), check_password(), and socket_read().
Referenced by start_network_thread().
02164 { 02165 /* Our job is simple: Send queued messages, retrying if necessary. Read frames 02166 from the network, and queue them for delivery to the channels */ 02167 int res; 02168 /* Establish I/O callback for socket read */ 02169 int *socket_read_id = ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL); 02170 02171 while (!dundi_shutdown) { 02172 res = ast_sched_wait(sched); 02173 if ((res > 1000) || (res < 0)) 02174 res = 1000; 02175 res = ast_io_wait(io, res); 02176 if (res >= 0) { 02177 AST_LIST_LOCK(&peers); 02178 ast_sched_runq(sched); 02179 AST_LIST_UNLOCK(&peers); 02180 } 02181 check_password(); 02182 } 02183 02184 ast_io_remove(io, socket_read_id); 02185 netthreadid = AST_PTHREADT_NULL; 02186 02187 return NULL; 02188 }
static int optimize_transactions | ( | struct dundi_request * | dr, | |
int | order | |||
) | [static] |
Definition at line 3337 of file pbx_dundi.c.
References ast_eid_cmp(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::dcontext, DUNDI_MAX_STACK, dundi_peer::eid, dundi_transaction::eidcount, dundi_transaction::eids, has_permission(), dundi_peer::include, dundi_peer::lastms, dundi_peer::order, dundi_transaction::them_eid, dundi_request::trans, and dundi_transaction::us_eid.
Referenced by dundi_lookup_internal(), dundi_precache_internal(), and dundi_query_eid_internal().
03338 { 03339 /* Minimize the message propagation through DUNDi by 03340 alerting the network to hops which should be not be considered */ 03341 struct dundi_transaction *trans; 03342 struct dundi_peer *peer; 03343 dundi_eid tmp; 03344 int x; 03345 int needpush; 03346 03347 AST_LIST_LOCK(&peers); 03348 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03349 /* Pop off the true root */ 03350 if (trans->eidcount) { 03351 tmp = trans->eids[--trans->eidcount]; 03352 needpush = 1; 03353 } else { 03354 tmp = trans->us_eid; 03355 needpush = 0; 03356 } 03357 03358 AST_LIST_TRAVERSE(&peers, peer, list) { 03359 if (ast_eid_cmp(&peer->eid, &empty_eid) && /* peer's eid is not empty (in case of dynamic peers) */ 03360 (peer->lastms > -1) && /* peer is reachable */ 03361 has_permission(&peer->include, dr->dcontext) && /* peer has destination context */ 03362 ast_eid_cmp(&peer->eid, &trans->them_eid) && /* peer is not transaction endpoint */ 03363 (peer->order <= order)) { 03364 /* For each other transaction, make sure we don't 03365 ask this EID about the others if they're not 03366 already in the list */ 03367 if (!ast_eid_cmp(&tmp, &peer->eid)) 03368 x = -1; 03369 else { 03370 for (x=0;x<trans->eidcount;x++) { 03371 if (!ast_eid_cmp(&trans->eids[x], &peer->eid)) 03372 break; 03373 } 03374 } 03375 if (x == trans->eidcount) { 03376 /* Nope not in the list, if needed, add us at the end since we're the source */ 03377 if (trans->eidcount < DUNDI_MAX_STACK - needpush) { 03378 trans->eids[trans->eidcount++] = peer->eid; 03379 /* Need to insert the real root (or us) at the bottom now as 03380 a requirement now. */ 03381 needpush = 1; 03382 } 03383 } 03384 } 03385 } 03386 /* If necessary, push the true root back on the end */ 03387 if (needpush) 03388 trans->eids[trans->eidcount++] = tmp; 03389 } 03390 AST_LIST_UNLOCK(&peers); 03391 03392 return 0; 03393 }
static void populate_addr | ( | struct dundi_peer * | peer, | |
dundi_eid * | eid | |||
) | [static] |
Definition at line 4329 of file pbx_dundi.c.
References dundi_peer::addr, ast_db_get(), ast_eid_to_str(), ast_sched_add(), do_register_expire(), and dundi_peer::registerexpire.
Referenced by build_peer().
04330 { 04331 char data[256]; 04332 char *c; 04333 int port, expire; 04334 char eid_str[20]; 04335 ast_eid_to_str(eid_str, sizeof(eid_str), eid); 04336 if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) { 04337 c = strchr(data, ':'); 04338 if (c) { 04339 *c = '\0'; 04340 c++; 04341 if (sscanf(c, "%5d:%30d", &port, &expire) == 2) { 04342 /* Got it! */ 04343 inet_aton(data, &peer->addr.sin_addr); 04344 peer->addr.sin_family = AF_INET; 04345 peer->addr.sin_port = htons(port); 04346 peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); 04347 } 04348 } 04349 } 04350 }
static int precache_trans | ( | struct dundi_transaction * | trans, | |
struct dundi_mapping * | maps, | |||
int | mapcount, | |||
int * | minexp, | |||
int * | foundanswers | |||
) | [static] |
Definition at line 3190 of file pbx_dundi.c.
References ast_log(), ast_sched_add(), dundi_transaction::autokillid, dundi_transaction::autokilltimeout, dundi_request::dcontext, 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, LOG_WARNING, dundi_request::number, dundi_transaction::parent, dundi_transaction::them_eid, dundi_transaction::ttl, dundi_transaction::us_eid, and dundi_result::weight.
Referenced by precache_transactions().
03191 { 03192 struct dundi_ie_data ied; 03193 int x, res; 03194 int max = 999999; 03195 int expiration = dundi_cache_time; 03196 int ouranswers=0; 03197 dundi_eid *avoid[1] = { NULL, }; 03198 int direct[1] = { 0, }; 03199 struct dundi_result dr[MAX_RESULTS]; 03200 struct dundi_hint_metadata hmd; 03201 if (!trans->parent) { 03202 ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); 03203 return -1; 03204 } 03205 memset(&hmd, 0, sizeof(hmd)); 03206 memset(&dr, 0, sizeof(dr)); 03207 /* Look up the answers we're going to include */ 03208 for (x=0;x<mapcount;x++) 03209 ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd); 03210 if (ouranswers < 0) 03211 ouranswers = 0; 03212 for (x=0;x<ouranswers;x++) { 03213 if (dr[x].weight < max) 03214 max = dr[x].weight; 03215 } 03216 if (max) { 03217 /* If we do not have a canonical result, keep looking */ 03218 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); 03219 if (res > 0) { 03220 /* Append answer in result */ 03221 ouranswers += res; 03222 } 03223 } 03224 03225 if (ouranswers > 0) { 03226 *foundanswers += ouranswers; 03227 memset(&ied, 0, sizeof(ied)); 03228 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03229 if (!dundi_eid_zero(&trans->us_eid)) 03230 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 03231 for (x=0;x<trans->eidcount;x++) 03232 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); 03233 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); 03234 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03235 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03236 for (x=0;x<ouranswers;x++) { 03237 /* Add answers */ 03238 if (dr[x].expiration && (expiration > dr[x].expiration)) 03239 expiration = dr[x].expiration; 03240 dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); 03241 } 03242 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 03243 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); 03244 if (trans->autokilltimeout) 03245 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03246 if (expiration < *minexp) 03247 *minexp = expiration; 03248 return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied); 03249 } else { 03250 /* Oops, nothing to send... */ 03251 destroy_trans(trans, 0); 03252 return 0; 03253 } 03254 }
static int precache_transactions | ( | struct dundi_request * | dr, | |
struct dundi_mapping * | maps, | |||
int | mapcount, | |||
int * | expiration, | |||
int * | foundanswers | |||
) | [static] |
Definition at line 3289 of file pbx_dundi.c.
References ast_debug, 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_WARNING, precache_trans(), dundi_transaction::thread, and dundi_request::trans.
Referenced by dundi_precache_internal().
03290 { 03291 struct dundi_transaction *trans; 03292 03293 /* Mark all as "in thread" so they don't disappear */ 03294 AST_LIST_LOCK(&peers); 03295 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03296 if (trans->thread) 03297 ast_log(LOG_WARNING, "This shouldn't happen, really...\n"); 03298 trans->thread = 1; 03299 } 03300 AST_LIST_UNLOCK(&peers); 03301 03302 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03303 if (!ast_test_flag(trans, FLAG_DEAD)) 03304 precache_trans(trans, maps, mapcount, expiration, foundanswers); 03305 } 03306 03307 /* Cleanup any that got destroyed in the mean time */ 03308 AST_LIST_LOCK(&peers); 03309 AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) { 03310 trans->thread = 0; 03311 if (ast_test_flag(trans, FLAG_DEAD)) { 03312 ast_debug(1, "Our transaction went away!\n"); 03313 /* This is going to remove the transaction from the dundi_request's list, as well 03314 * as the global transactions list */ 03315 destroy_trans(trans, 0); 03316 } 03317 } 03318 AST_LIST_TRAVERSE_SAFE_END 03319 AST_LIST_UNLOCK(&peers); 03320 03321 return 0; 03322 }
static void* process_clearcache | ( | void * | ignore | ) | [static] |
Definition at line 2190 of file pbx_dundi.c.
References ast_db_del(), ast_db_freetree(), ast_db_gettree(), ast_debug, ast_get_time_t(), AST_PTHREADT_NULL, ast_db_entry::data, ast_db_entry::key, and ast_db_entry::next.
Referenced by start_network_thread().
02191 { 02192 struct ast_db_entry *db_entry, *db_tree; 02193 int striplen = sizeof("/dundi/cache"); 02194 time_t now; 02195 02196 while (!dundi_shutdown) { 02197 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 02198 02199 time(&now); 02200 02201 db_entry = db_tree = ast_db_gettree("dundi/cache", NULL); 02202 for (; db_entry; db_entry = db_entry->next) { 02203 time_t expiry; 02204 02205 if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) { 02206 if (expiry < now) { 02207 ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key); 02208 ast_db_del("dundi/cache", db_entry->key + striplen); 02209 } 02210 } 02211 } 02212 ast_db_freetree(db_tree); 02213 02214 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 02215 pthread_testcancel(); 02216 sleep(60); 02217 pthread_testcancel(); 02218 } 02219 02220 clearcachethreadid = AST_PTHREADT_NULL; 02221 return NULL; 02222 }
static void* process_precache | ( | void * | ign | ) | [static] |
Definition at line 2224 of file pbx_dundi.c.
References ast_copy_string(), ast_free, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, AST_PTHREADT_NULL, dundi_precache_queue::context, dundi_precache(), dundi_precache_queue::expiration, and dundi_precache_queue::number.
Referenced by start_network_thread().
02225 { 02226 struct dundi_precache_queue *qe; 02227 time_t now; 02228 char context[256]; 02229 char number[256]; 02230 int run; 02231 02232 while (!dundi_shutdown) { 02233 time(&now); 02234 run = 0; 02235 AST_LIST_LOCK(&pcq); 02236 if ((qe = AST_LIST_FIRST(&pcq))) { 02237 if (!qe->expiration) { 02238 /* Gone... Remove... */ 02239 AST_LIST_REMOVE_HEAD(&pcq, list); 02240 ast_free(qe); 02241 } else if (qe->expiration < now) { 02242 /* Process this entry */ 02243 qe->expiration = 0; 02244 ast_copy_string(context, qe->context, sizeof(context)); 02245 ast_copy_string(number, qe->number, sizeof(number)); 02246 run = 1; 02247 } 02248 } 02249 AST_LIST_UNLOCK(&pcq); 02250 if (run) { 02251 dundi_precache(context, number); 02252 } else 02253 sleep(1); 02254 } 02255 02256 precachethreadid = AST_PTHREADT_NULL; 02257 02258 return NULL; 02259 }
static void prune_mappings | ( | void | ) | [static] |
Definition at line 4168 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(), and map.
Referenced by set_config(), and unload_module().
04169 { 04170 struct dundi_mapping *map; 04171 04172 AST_LIST_LOCK(&peers); 04173 AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) { 04174 if (map->dead) { 04175 AST_LIST_REMOVE_CURRENT(list); 04176 destroy_map(map); 04177 } 04178 } 04179 AST_LIST_TRAVERSE_SAFE_END; 04180 AST_LIST_UNLOCK(&peers); 04181 }
static void prune_peers | ( | void | ) | [static] |
Definition at line 4153 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_peer::dead, and destroy_peer().
Referenced by set_config(), and unload_module().
04154 { 04155 struct dundi_peer *peer; 04156 04157 AST_LIST_LOCK(&peers); 04158 AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) { 04159 if (peer->dead) { 04160 AST_LIST_REMOVE_CURRENT(list); 04161 destroy_peer(peer); 04162 } 04163 } 04164 AST_LIST_TRAVERSE_SAFE_END; 04165 AST_LIST_UNLOCK(&peers); 04166 }
static void qualify_peer | ( | struct dundi_peer * | peer, | |
int | schedonly | |||
) | [static] |
Definition at line 4306 of file pbx_dundi.c.
References ast_sched_add(), AST_SCHED_DEL, ast_set_flag, ast_tvnow(), create_transaction(), destroy_trans(), do_qualify(), DUNDI_COMMAND_NULL, dundi_send(), FLAG_ISQUAL, dundi_peer::lastms, dundi_peer::maxms, dundi_peer::qualifyid, dundi_peer::qualtrans, and dundi_peer::qualtx.
Referenced by build_peer(), do_qualify(), and handle_command_response().
04307 { 04308 int when; 04309 AST_SCHED_DEL(sched, peer->qualifyid); 04310 if (peer->qualtrans) 04311 destroy_trans(peer->qualtrans, 0); 04312 peer->qualtrans = NULL; 04313 if (peer->maxms > 0) { 04314 when = 60000; 04315 if (peer->lastms < 0) 04316 when = 10000; 04317 if (schedonly) 04318 when = 5000; 04319 peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer); 04320 if (!schedonly) 04321 peer->qualtrans = create_transaction(peer); 04322 if (peer->qualtrans) { 04323 peer->qualtx = ast_tvnow(); 04324 ast_set_flag(peer->qualtrans, FLAG_ISQUAL); 04325 dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL); 04326 } 04327 } 04328 }
static int query_transactions | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3324 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_query(), and dundi_request::trans.
Referenced by dundi_query_eid_internal().
03325 { 03326 struct dundi_transaction *trans; 03327 03328 AST_LIST_LOCK(&peers); 03329 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03330 dundi_query(trans); 03331 } 03332 AST_LIST_UNLOCK(&peers); 03333 03334 return 0; 03335 }
static int register_request | ( | struct dundi_request * | dr, | |
struct dundi_request ** | pending | |||
) | [static] |
Definition at line 3510 of file pbx_dundi.c.
References ast_debug, ast_eid_cmp(), ast_eid_to_str(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dundi_request::crc32, dundi_request::dcontext, dundi_request::number, and dundi_request::root_eid.
Referenced by dundi_lookup_internal().
03511 { 03512 struct dundi_request *cur; 03513 int res=0; 03514 char eid_str[20]; 03515 AST_LIST_LOCK(&peers); 03516 AST_LIST_TRAVERSE(&requests, cur, list) { 03517 ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number, 03518 dr->dcontext, dr->number); 03519 if (!strcasecmp(cur->dcontext, dr->dcontext) && 03520 !strcasecmp(cur->number, dr->number) && 03521 (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) { 03522 ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 03523 cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32); 03524 *pending = cur; 03525 res = 1; 03526 break; 03527 } 03528 } 03529 if (!res) { 03530 ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 03531 dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32); 03532 /* Go ahead and link us in since nobody else is searching for this */ 03533 AST_LIST_INSERT_HEAD(&requests, dr, list); 03534 *pending = NULL; 03535 } 03536 AST_LIST_UNLOCK(&peers); 03537 return res; 03538 }
static int reload | ( | void | ) | [static] |
Definition at line 4799 of file pbx_dundi.c.
References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().
04800 { 04801 struct sockaddr_in sin; 04802 04803 if (set_config("dundi.conf", &sin, 1)) 04804 return AST_MODULE_LOAD_FAILURE; 04805 04806 return AST_MODULE_LOAD_SUCCESS; 04807 }
static void reschedule_precache | ( | const char * | number, | |
const char * | context, | |||
int | expiration | |||
) | [static] |
Definition at line 3689 of file pbx_dundi.c.
References ast_calloc, AST_LIST_FIRST, AST_LIST_INSERT_AFTER, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, dundi_precache_queue::context, dundi_precache_queue::expiration, len(), and dundi_precache_queue::number.
Referenced by dundi_precache_full(), and dundi_precache_internal().
03690 { 03691 int len; 03692 struct dundi_precache_queue *qe, *prev; 03693 03694 AST_LIST_LOCK(&pcq); 03695 AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) { 03696 if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) { 03697 AST_LIST_REMOVE_CURRENT(list); 03698 break; 03699 } 03700 } 03701 AST_LIST_TRAVERSE_SAFE_END; 03702 if (!qe) { 03703 len = sizeof(*qe); 03704 len += strlen(number) + 1; 03705 len += strlen(context) + 1; 03706 if (!(qe = ast_calloc(1, len))) { 03707 AST_LIST_UNLOCK(&pcq); 03708 return; 03709 } 03710 strcpy(qe->number, number); 03711 qe->context = qe->number + strlen(number) + 1; 03712 strcpy(qe->context, context); 03713 } 03714 time(&qe->expiration); 03715 qe->expiration += expiration; 03716 if ((prev = AST_LIST_FIRST(&pcq))) { 03717 while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration)) 03718 prev = AST_LIST_NEXT(prev, list); 03719 AST_LIST_INSERT_AFTER(&pcq, prev, qe, list); 03720 } else 03721 AST_LIST_INSERT_HEAD(&pcq, qe, list); 03722 AST_LIST_UNLOCK(&pcq); 03723 }
static int rescomp | ( | const void * | a, | |
const void * | b | |||
) | [static] |
Definition at line 2403 of file pbx_dundi.c.
References dundi_result::weight.
Referenced by sort_results().
02404 { 02405 const struct dundi_result *resa, *resb; 02406 resa = a; 02407 resb = b; 02408 if (resa->weight < resb->weight) 02409 return -1; 02410 if (resa->weight > resb->weight) 02411 return 1; 02412 return 0; 02413 }
static int reset_transaction | ( | struct dundi_transaction * | trans | ) | [static] |
Definition at line 488 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().
00489 { 00490 int tid; 00491 tid = get_trans_id(); 00492 if (tid < 1) 00493 return -1; 00494 trans->strans = tid; 00495 trans->dtrans = 0; 00496 trans->iseqno = 0; 00497 trans->oiseqno = 0; 00498 trans->oseqno = 0; 00499 trans->aseqno = 0; 00500 ast_clear_flag(trans, FLAG_FINAL); 00501 return 0; 00502 }
static void save_secret | ( | const char * | newkey, | |
const char * | oldkey | |||
) | [static] |
Definition at line 2094 of file pbx_dundi.c.
References ast_db_put(), and DUNDI_SECRET_TIME.
Referenced by check_password(), and load_password().
02095 { 02096 char tmp[256]; 02097 if (oldkey) 02098 snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey); 02099 else 02100 snprintf(tmp, sizeof(tmp), "%s", newkey); 02101 rotatetime = time(NULL) + DUNDI_SECRET_TIME; 02102 ast_db_put(secretpath, "secret", tmp); 02103 snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime); 02104 ast_db_put(secretpath, "secretexpiry", tmp); 02105 }
static int set_config | ( | char * | config_file, | |
struct sockaddr_in * | sin, | |||
int | reload | |||
) | [static] |
Definition at line 4621 of file pbx_dundi.c.
References any_peer, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_eid_default, ast_gethostbyname(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_str2tos(), ast_str_to_eid(), ast_true(), ast_variable_browse(), build_mapping(), build_peer(), CONFIG_STATUS_FILEINVALID, DEFAULT_MAXMS, DUNDI_DEFAULT_CACHE_TIME, DUNDI_DEFAULT_TTL, DUNDI_MODEL_OUTBOUND, dundi_precache_full(), find_peer(), hp, ast_variable::lineno, load_password(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mark_mappings(), mark_peers(), MAXHOSTNAMELEN, ast_variable::name, ast_variable::next, prune_mappings(), prune_peers(), and ast_variable::value.
Referenced by load_module(), and reload().
04622 { 04623 struct ast_config *cfg; 04624 struct ast_variable *v; 04625 char *cat; 04626 int x; 04627 struct ast_flags config_flags = { 0 }; 04628 char hn[MAXHOSTNAMELEN] = ""; 04629 struct ast_hostent he; 04630 struct hostent *hp; 04631 struct sockaddr_in sin2; 04632 static int last_port = 0; 04633 int globalpcmodel = 0; 04634 dundi_eid testeid; 04635 04636 if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { 04637 ast_log(LOG_ERROR, "Unable to load config %s\n", config_file); 04638 return -1; 04639 } 04640 04641 dundi_ttl = DUNDI_DEFAULT_TTL; 04642 dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME; 04643 any_peer = NULL; 04644 04645 ipaddr[0] = '\0'; 04646 if (!gethostname(hn, sizeof(hn)-1)) { 04647 hp = ast_gethostbyname(hn, &he); 04648 if (hp) { 04649 memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr)); 04650 ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr)); 04651 } else 04652 ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn); 04653 } else 04654 ast_log(LOG_WARNING, "Unable to get host name!\n"); 04655 AST_LIST_LOCK(&peers); 04656 04657 memcpy(&global_eid, &ast_eid_default, sizeof(global_eid)); 04658 04659 global_storehistory = 0; 04660 ast_copy_string(secretpath, "dundi", sizeof(secretpath)); 04661 v = ast_variable_browse(cfg, "general"); 04662 while(v) { 04663 if (!strcasecmp(v->name, "port")){ 04664 sin->sin_port = htons(atoi(v->value)); 04665 if(last_port==0){ 04666 last_port=sin->sin_port; 04667 } else if(sin->sin_port != last_port) 04668 ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); 04669 } else if (!strcasecmp(v->name, "bindaddr")) { 04670 struct hostent *hep; 04671 struct ast_hostent hent; 04672 hep = ast_gethostbyname(v->value, &hent); 04673 if (hep) { 04674 memcpy(&sin->sin_addr, hep->h_addr, sizeof(sin->sin_addr)); 04675 } else 04676 ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value); 04677 } else if (!strcasecmp(v->name, "authdebug")) { 04678 authdebug = ast_true(v->value); 04679 } else if (!strcasecmp(v->name, "ttl")) { 04680 if ((sscanf(v->value, "%30d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) { 04681 dundi_ttl = x; 04682 } else { 04683 ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n", 04684 v->value, v->lineno, DUNDI_DEFAULT_TTL); 04685 } 04686 } else if (!strcasecmp(v->name, "autokill")) { 04687 if (sscanf(v->value, "%30d", &x) == 1) { 04688 if (x >= 0) 04689 global_autokilltimeout = x; 04690 else 04691 ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno); 04692 } else if (ast_true(v->value)) { 04693 global_autokilltimeout = DEFAULT_MAXMS; 04694 } else { 04695 global_autokilltimeout = 0; 04696 } 04697 } else if (!strcasecmp(v->name, "entityid")) { 04698 if (!ast_str_to_eid(&testeid, v->value)) 04699 global_eid = testeid; 04700 else 04701 ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno); 04702 } else if (!strcasecmp(v->name, "tos")) { 04703 if (ast_str2tos(v->value, &tos)) 04704 ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno); 04705 } else if (!strcasecmp(v->name, "department")) { 04706 ast_copy_string(dept, v->value, sizeof(dept)); 04707 } else if (!strcasecmp(v->name, "organization")) { 04708 ast_copy_string(org, v->value, sizeof(org)); 04709 } else if (!strcasecmp(v->name, "locality")) { 04710 ast_copy_string(locality, v->value, sizeof(locality)); 04711 } else if (!strcasecmp(v->name, "stateprov")) { 04712 ast_copy_string(stateprov, v->value, sizeof(stateprov)); 04713 } else if (!strcasecmp(v->name, "country")) { 04714 ast_copy_string(country, v->value, sizeof(country)); 04715 } else if (!strcasecmp(v->name, "email")) { 04716 ast_copy_string(email, v->value, sizeof(email)); 04717 } else if (!strcasecmp(v->name, "phone")) { 04718 ast_copy_string(phone, v->value, sizeof(phone)); 04719 } else if (!strcasecmp(v->name, "storehistory")) { 04720 global_storehistory = ast_true(v->value); 04721 } else if (!strcasecmp(v->name, "cachetime")) { 04722 if ((sscanf(v->value, "%30d", &x) == 1)) { 04723 dundi_cache_time = x; 04724 } else { 04725 ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n", 04726 v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME); 04727 } 04728 } 04729 v = v->next; 04730 } 04731 AST_LIST_UNLOCK(&peers); 04732 mark_mappings(); 04733 v = ast_variable_browse(cfg, "mappings"); 04734 while(v) { 04735 build_mapping(v->name, v->value); 04736 v = v->next; 04737 } 04738 prune_mappings(); 04739 mark_peers(); 04740 cat = ast_category_browse(cfg, NULL); 04741 while(cat) { 04742 if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) { 04743 /* Entries */ 04744 if (!ast_str_to_eid(&testeid, cat)) 04745 build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel); 04746 else if (!strcasecmp(cat, "*")) { 04747 build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel); 04748 any_peer = find_peer(NULL); 04749 } else 04750 ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat); 04751 } 04752 cat = ast_category_browse(cfg, cat); 04753 } 04754 prune_peers(); 04755 ast_config_destroy(cfg); 04756 load_password(); 04757 if (globalpcmodel & DUNDI_MODEL_OUTBOUND) 04758 dundi_precache_full(); 04759 return 0; 04760 }
static int socket_read | ( | int * | id, | |
int | fd, | |||
short | events, | |||
void * | cbdata | |||
) | [static] |
Definition at line 2051 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), dundi_showframe(), errno, handle_frame(), len(), LOG_WARNING, and MAX_PACKET_SIZE.
Referenced by network_thread().
02052 { 02053 struct sockaddr_in sin; 02054 int res; 02055 struct dundi_hdr *h; 02056 char buf[MAX_PACKET_SIZE]; 02057 socklen_t len = sizeof(sin); 02058 02059 res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len); 02060 if (res < 0) { 02061 if (errno != ECONNREFUSED) 02062 ast_log(LOG_WARNING, "Error: %s\n", strerror(errno)); 02063 return 1; 02064 } 02065 if (res < sizeof(struct dundi_hdr)) { 02066 ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr)); 02067 return 1; 02068 } 02069 buf[res] = '\0'; 02070 h = (struct dundi_hdr *) buf; 02071 if (dundidebug) 02072 dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr)); 02073 AST_LIST_LOCK(&peers); 02074 handle_frame(h, &sin, res - sizeof(struct dundi_hdr)); 02075 AST_LIST_UNLOCK(&peers); 02076 return 1; 02077 }
static void sort_results | ( | struct dundi_result * | results, | |
int | count | |||
) | [static] |
Definition at line 2415 of file pbx_dundi.c.
References rescomp().
Referenced by dundi_do_lookup(), dundi_exec(), dundi_query_read(), and dundifunc_read().
02416 { 02417 qsort(results, count, sizeof(results[0]), rescomp); 02418 }
static int start_network_thread | ( | void | ) | [static] |
Definition at line 2261 of file pbx_dundi.c.
References ast_pthread_create_background, network_thread(), process_clearcache(), and process_precache().
Referenced by load_module().
02262 { 02263 ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL); 02264 ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL); 02265 ast_pthread_create_background(&clearcachethreadid, NULL, process_clearcache, NULL); 02266 return 0; 02267 }
static int str2tech | ( | char * | str | ) | [static] |
Definition at line 387 of file pbx_dundi.c.
References DUNDI_PROTO_H323, DUNDI_PROTO_IAX, and DUNDI_PROTO_SIP.
Referenced by build_mapping().
00388 { 00389 if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) 00390 return DUNDI_PROTO_IAX; 00391 else if (!strcasecmp(str, "SIP")) 00392 return DUNDI_PROTO_SIP; 00393 else if (!strcasecmp(str, "H323")) 00394 return DUNDI_PROTO_H323; 00395 else 00396 return -1; 00397 }
static char* tech2str | ( | int | tech | ) | [static] |
Definition at line 371 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().
00372 { 00373 switch(tech) { 00374 case DUNDI_PROTO_NONE: 00375 return "None"; 00376 case DUNDI_PROTO_IAX: 00377 return "IAX2"; 00378 case DUNDI_PROTO_SIP: 00379 return "SIP"; 00380 case DUNDI_PROTO_H323: 00381 return "H323"; 00382 default: 00383 return "Unknown"; 00384 } 00385 }
static int unload_module | ( | void | ) | [static] |
Definition at line 4762 of file pbx_dundi.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_PTHREADT_NULL, ast_unregister_switch(), io_context_destroy(), mark_mappings(), mark_peers(), prune_mappings(), prune_peers(), and sched_context_destroy().
04763 { 04764 pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid, previous_clearcachethreadid = clearcachethreadid; 04765 04766 ast_cli_unregister_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); 04767 ast_unregister_switch(&dundi_switch); 04768 ast_custom_function_unregister(&dundi_function); 04769 ast_custom_function_unregister(&dundi_query_function); 04770 ast_custom_function_unregister(&dundi_result_function); 04771 04772 /* Stop all currently running threads */ 04773 dundi_shutdown = 1; 04774 if (previous_netthreadid != AST_PTHREADT_NULL) { 04775 pthread_kill(previous_netthreadid, SIGURG); 04776 pthread_join(previous_netthreadid, NULL); 04777 } 04778 if (previous_precachethreadid != AST_PTHREADT_NULL) { 04779 pthread_kill(previous_precachethreadid, SIGURG); 04780 pthread_join(previous_precachethreadid, NULL); 04781 } 04782 if (previous_clearcachethreadid != AST_PTHREADT_NULL) { 04783 pthread_cancel(previous_clearcachethreadid); 04784 pthread_join(previous_clearcachethreadid, NULL); 04785 } 04786 04787 close(netsocket); 04788 io_context_destroy(io); 04789 sched_context_destroy(sched); 04790 04791 mark_mappings(); 04792 prune_mappings(); 04793 mark_peers(); 04794 prune_peers(); 04795 04796 return 0; 04797 }
static void unregister_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3540 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, and AST_LIST_UNLOCK.
Referenced by dundi_lookup_internal().
03541 { 03542 AST_LIST_LOCK(&peers); 03543 AST_LIST_REMOVE(&requests, dr, list); 03544 AST_LIST_UNLOCK(&peers); 03545 }
static int update_key | ( | struct dundi_peer * | peer | ) | [static] |
Definition at line 1312 of file pbx_dundi.c.
References ast_aes_set_decrypt_key(), ast_aes_set_encrypt_key(), ast_eid_to_str(), ast_encrypt_bin(), ast_key_get(), AST_KEY_PRIVATE, AST_KEY_PUBLIC, ast_log(), ast_sign_bin(), build_iv(), dundi_peer::eid, dundi_peer::inkey, dundi_peer::keyexpire, LOG_NOTICE, dundi_peer::outkey, dundi_peer::sentfullkey, dundi_peer::txenckey, dundi_peer::us_dcx, dundi_peer::us_ecx, and dundi_peer::us_keycrc32.
Referenced by dundi_encrypt().
01313 { 01314 unsigned char key[16]; 01315 struct ast_key *ekey, *skey; 01316 char eid_str[20]; 01317 int res; 01318 if (!peer->keyexpire || (peer->keyexpire < time(NULL))) { 01319 build_iv(key); 01320 ast_aes_set_encrypt_key(key, &peer->us_ecx); 01321 ast_aes_set_decrypt_key(key, &peer->us_dcx); 01322 ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC); 01323 if (!ekey) { 01324 ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n", 01325 peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01326 return -1; 01327 } 01328 skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE); 01329 if (!skey) { 01330 ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n", 01331 peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01332 return -1; 01333 } 01334 if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) { 01335 ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128); 01336 return -1; 01337 } 01338 if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) { 01339 ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res); 01340 return -1; 01341 } 01342 peer->us_keycrc32 = crc32(0L, peer->txenckey, 128); 01343 peer->sentfullkey = 0; 01344 /* Looks good */ 01345 time(&peer->keyexpire); 01346 peer->keyexpire += dundi_key_ttl; 01347 } 01348 return 0; 01349 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Distributed Universal Number Discovery (DUNDi)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .nonoptreq = "res_crypto", } [static] |
Definition at line 4867 of file pbx_dundi.c.
struct dundi_peer* any_peer [static] |
Wildcard peer.
This peer is created if the [*] entry is specified in dundi.conf
Definition at line 343 of file pbx_dundi.c.
Referenced by find_peer(), handle_command_response(), and set_config().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 4867 of file pbx_dundi.c.
int authdebug = 0 [static] |
Definition at line 184 of file pbx_dundi.c.
pthread_t clearcachethreadid = AST_PTHREADT_NULL [static] |
Definition at line 181 of file pbx_dundi.c.
struct ast_cli_entry cli_dundi[] [static] |
Definition at line 2884 of file pbx_dundi.c.
char country[80] [static] |
Definition at line 196 of file pbx_dundi.c.
Referenced by load_indications(), and SendDialTone().
char cursecret[80] [static] |
Definition at line 200 of file pbx_dundi.c.
int default_expiration = 60 [static] |
Definition at line 190 of file pbx_dundi.c.
char dept[80] [static] |
Definition at line 192 of file pbx_dundi.c.
int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME [static] |
Definition at line 187 of file pbx_dundi.c.
int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE [static] |
Definition at line 186 of file pbx_dundi.c.
struct ast_custom_function dundi_query_function [static] |
{ .name = "DUNDIQUERY", .read = dundi_query_read, }
Definition at line 4027 of file pbx_dundi.c.
struct ast_app_option dundi_query_opts[128] = { [ 'b' ] = { .flag = OPT_BYPASS_CACHE }, } [static] |
Definition at line 3888 of file pbx_dundi.c.
Referenced by dundi_query_read(), and dundifunc_read().
struct ast_datastore_info dundi_result_datastore_info [static] |
{ .type = "DUNDIQUERY", .destroy = drds_destroy_cb, }
Definition at line 3963 of file pbx_dundi.c.
struct ast_custom_function dundi_result_function [static] |
{ .name = "DUNDIRESULT", .read = dundi_result_read, }
Definition at line 4101 of file pbx_dundi.c.
unsigned int dundi_result_id [static] |
Definition at line 3944 of file pbx_dundi.c.
int dundi_shutdown = 0 [static] |
Definition at line 204 of file pbx_dundi.c.
struct ast_switch dundi_switch [static] |
Definition at line 4612 of file pbx_dundi.c.
int dundi_ttl = DUNDI_DEFAULT_TTL [static] |
Definition at line 185 of file pbx_dundi.c.
int dundidebug = 0 [static] |
Definition at line 183 of file pbx_dundi.c.
char email[80] [static] |
Definition at line 197 of file pbx_dundi.c.
Definition at line 203 of file pbx_dundi.c.
int global_autokilltimeout = 0 [static] |
Definition at line 188 of file pbx_dundi.c.
dundi_eid global_eid [static] |
Definition at line 189 of file pbx_dundi.c.
int global_storehistory = 0 [static] |
Definition at line 191 of file pbx_dundi.c.
struct io_context* io [static] |
Definition at line 176 of file pbx_dundi.c.
char ipaddr[80] [static] |
Definition at line 201 of file pbx_dundi.c.
Referenced by realtime_peer(), and realtime_update_peer().
char locality[80] [static] |
Definition at line 194 of file pbx_dundi.c.
int netsocket = -1 [static] |
Definition at line 178 of file pbx_dundi.c.
Referenced by ast_netsock_bindaddr(), and handle_error().
pthread_t netthreadid = AST_PTHREADT_NULL [static] |
Definition at line 179 of file pbx_dundi.c.
char org[80] [static] |
Definition at line 193 of file pbx_dundi.c.
Referenced by calc_crc().
char phone[80] [static] |
Definition at line 198 of file pbx_dundi.c.
Referenced by privacy_exec().
pthread_t precachethreadid = AST_PTHREADT_NULL [static] |
Definition at line 180 of file pbx_dundi.c.
time_t rotatetime [static] |
Definition at line 202 of file pbx_dundi.c.
struct sched_context* sched [static] |
Definition at line 177 of file pbx_dundi.c.
char secretpath[80] [static] |
Definition at line 199 of file pbx_dundi.c.
char stateprov[80] [static] |
Definition at line 195 of file pbx_dundi.c.
unsigned int tos = 0 [static] |
Definition at line 182 of file pbx_dundi.c.