#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/aes.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_peer::permissionlist |
| struct | dundi_precache_queue |
| struct | dundi_query_state |
| struct | dundi_request |
| struct | dundi_result_datastore |
| struct | dundi_transaction |
| struct | dundi_transaction::packetlist |
| struct | mappings |
| struct | pcq |
| struct | peers |
| struct | permission |
| 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 %-10.10s %-8.8s %-15.15s\n" |
| #define | FORMAT2 "%-12.12s %-12.12s %-10.10s\n" |
| #define | FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
| #define | FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" |
| #define | FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" |
| #define | FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n" |
| #define | 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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| 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 |
Definition in file pbx_dundi.c.
| #define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17) |
| #define DUNDI_MODEL_INBOUND (1 << 0) |
Definition at line 74 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 75 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) |
| #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME |
| #define DUNDI_TIMING_HISTORY 10 |
Keep times of last 10 lookups
Definition at line 79 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 %-10.10s %-8.8s %-15.15s\n" |
| #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n" |
| #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" |
| #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" |
| #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" |
| #define FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n" |
| #define MAX_OPTS 128 |
| #define MAX_PACKET_SIZE 8192 |
Definition at line 70 of file pbx_dundi.c.
Referenced by handle_command_response(), and socket_read().
| #define MAX_RESULTS 64 |
Definition at line 68 of file pbx_dundi.c.
| #define MAX_WEIGHT 59999 |
| 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 81 of file pbx_dundi.c.
00081 { 00082 FLAG_ISREG = (1 << 0), /*!< Transaction is register request */ 00083 FLAG_DEAD = (1 << 1), /*!< Transaction is dead */ 00084 FLAG_FINAL = (1 << 2), /*!< Transaction has final message sent */ 00085 FLAG_ISQUAL = (1 << 3), /*!< Transaction is a qualification */ 00086 FLAG_ENCRYPT = (1 << 4), /*!< Transaction is encrypted wiht ECX/DCX */ 00087 FLAG_SENDFULLKEY = (1 << 5), /*!< Send full key on transaction */ 00088 FLAG_STOREHIST = (1 << 6), /*!< Record historic performance */ 00089 };
| anonymous enum |
| static void __reg_module | ( | void | ) | [static] |
Definition at line 4827 of file pbx_dundi.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 4827 of file pbx_dundi.c.
| static void abort_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3362 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().
03363 { 03364 struct dundi_transaction *trans; 03365 03366 AST_LIST_LOCK(&peers); 03367 while ((trans = AST_LIST_FIRST(&dr->trans))) { 03368 /* This will remove the transaction from the list */ 03369 destroy_trans(trans, 0); 03370 } 03371 AST_LIST_UNLOCK(&peers); 03372 }
| static int ack_trans | ( | struct dundi_transaction * | trans, | |
| int | iseqno | |||
| ) | [static] |
Definition at line 1916 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().
01917 { 01918 struct dundi_packet *pack; 01919 01920 /* Ack transmitted packet corresponding to iseqno */ 01921 AST_LIST_TRAVERSE(&trans->packets, pack, list) { 01922 if ((pack->h->oseqno + 1) % 255 == iseqno) { 01923 destroy_packet(pack, 0); 01924 if (!AST_LIST_EMPTY(&trans->lasttrans)) { 01925 ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n"); 01926 destroy_packets(&trans->lasttrans); 01927 } 01928 AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list); 01929 AST_SCHED_DEL(sched, trans->autokillid); 01930 return 1; 01931 } 01932 } 01933 01934 return 0; 01935 }
| static void append_permission | ( | struct permissionlist * | permlist, | |
| const char * | s, | |||
| int | allow | |||
| ) | [static] |
Definition at line 4148 of file pbx_dundi.c.
References permission::allow, ast_calloc, AST_LIST_INSERT_TAIL, and permission::name.
Referenced by build_peer().
04149 { 04150 struct permission *perm; 04151 04152 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1))) 04153 return; 04154 04155 strcpy(perm->name, s); 04156 perm->allow = allow; 04157 04158 AST_LIST_INSERT_TAIL(permlist, perm, list); 04159 }
| static int append_transaction | ( | struct dundi_request * | dr, | |
| struct dundi_peer * | p, | |||
| int | ttl, | |||
| dundi_eid * | avoid[] | |||
| ) | [static] |
Definition at line 3317 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().
03318 { 03319 struct dundi_transaction *trans; 03320 int x; 03321 char eid_str[20]; 03322 char eid_str2[20]; 03323 03324 /* Ignore if not registered */ 03325 if (!p->addr.sin_addr.s_addr) 03326 return 0; 03327 if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms))) 03328 return 0; 03329 03330 if (ast_strlen_zero(dr->number)) 03331 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); 03332 else 03333 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); 03334 03335 trans = create_transaction(p); 03336 if (!trans) 03337 return -1; 03338 trans->parent = dr; 03339 trans->ttl = ttl; 03340 for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++) 03341 trans->eids[x] = *avoid[x]; 03342 trans->eidcount = x; 03343 AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist); 03344 03345 return 0; 03346 }
| static void apply_peer | ( | struct dundi_transaction * | trans, | |
| struct dundi_peer * | p | |||
| ) | [static] |
Definition at line 1195 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().
01196 { 01197 if (!trans->addr.sin_addr.s_addr) 01198 memcpy(&trans->addr, &p->addr, sizeof(trans->addr)); 01199 trans->us_eid = p->us_eid; 01200 trans->them_eid = p->eid; 01201 /* Enable encryption if appropriate */ 01202 if (!ast_strlen_zero(p->inkey)) 01203 ast_set_flag(trans, FLAG_ENCRYPT); 01204 if (p->maxms) { 01205 trans->autokilltimeout = p->maxms; 01206 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 01207 if (p->lastms > 1) { 01208 trans->retranstimer = p->lastms * 2; 01209 /* Keep it from being silly */ 01210 if (trans->retranstimer < 150) 01211 trans->retranstimer = 150; 01212 } 01213 if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER) 01214 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 01215 } else 01216 trans->autokilltimeout = global_autokilltimeout; 01217 }
| static unsigned long avoid_crc32 | ( | dundi_eid * | avoid[] | ) | [static] |
Definition at line 3483 of file pbx_dundi.c.
References dundi_request::crc32.
Referenced by dundi_lookup_internal().
03484 { 03485 /* Idea is that we're calculating a checksum which is independent of 03486 the order that the EID's are listed in */ 03487 uint32_t acrc32 = 0; 03488 int x; 03489 for (x=0;avoid[x];x++) { 03490 /* Order doesn't matter */ 03491 if (avoid[x+1]) { 03492 acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid)); 03493 } 03494 } 03495 return acrc32; 03496 }
| static void build_iv | ( | unsigned char * | iv | ) | [static] |
Definition at line 445 of file pbx_dundi.c.
References ast_random().
Referenced by build_secret(), dundi_encrypt(), and update_key().
00446 { 00447 /* XXX Would be nice to be more random XXX */ 00448 unsigned int *fluffy; 00449 int x; 00450 fluffy = (unsigned int *)(iv); 00451 for (x=0;x<4;x++) 00452 fluffy[x] = ast_random(); 00453 }
| static void build_mapping | ( | const char * | name, | |
| const char * | value | |||
| ) | [static] |
Definition at line 4163 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().
04164 { 04165 char *t, *fields[MAX_OPTS]; 04166 struct dundi_mapping *map; 04167 int x; 04168 int y; 04169 04170 t = ast_strdupa(value); 04171 04172 AST_LIST_TRAVERSE(&mappings, map, list) { 04173 /* Find a double match */ 04174 if (!strcasecmp(map->dcontext, name) && 04175 (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && 04176 (!value[strlen(map->lcontext)] || 04177 (value[strlen(map->lcontext)] == ',')))) 04178 break; 04179 } 04180 if (!map) { 04181 if (!(map = ast_calloc(1, sizeof(*map)))) 04182 return; 04183 AST_LIST_INSERT_HEAD(&mappings, map, list); 04184 map->dead = 1; 04185 } 04186 map->options = 0; 04187 memset(fields, 0, sizeof(fields)); 04188 x = 0; 04189 while (t && x < MAX_OPTS) { 04190 fields[x++] = t; 04191 t = strchr(t, ','); 04192 if (t) { 04193 *t = '\0'; 04194 t++; 04195 } 04196 } /* Russell was here, arrrr! */ 04197 if ((x == 1) && ast_strlen_zero(fields[0])) { 04198 /* Placeholder mapping */ 04199 ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); 04200 map->dead = 0; 04201 } else if (x >= 4) { 04202 ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); 04203 ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext)); 04204 if ((sscanf(fields[1], "%30d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) { 04205 ast_copy_string(map->dest, fields[3], sizeof(map->dest)); 04206 if ((map->tech = str2tech(fields[2]))) 04207 map->dead = 0; 04208 } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') { 04209 map->weightstr = ast_strdup(fields[1]); 04210 ast_copy_string(map->dest, fields[3], sizeof(map->dest)); 04211 if ((map->tech = str2tech(fields[2]))) 04212 map->dead = 0; 04213 } else { 04214 ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext); 04215 } 04216 for (y = 4;y < x; y++) { 04217 if (!strcasecmp(fields[y], "nounsolicited")) 04218 map->options |= DUNDI_FLAG_NOUNSOLICITED; 04219 else if (!strcasecmp(fields[y], "nocomunsolicit")) 04220 map->options |= DUNDI_FLAG_NOCOMUNSOLICIT; 04221 else if (!strcasecmp(fields[y], "residential")) 04222 map->options |= DUNDI_FLAG_RESIDENTIAL; 04223 else if (!strcasecmp(fields[y], "commercial")) 04224 map->options |= DUNDI_FLAG_COMMERCIAL; 04225 else if (!strcasecmp(fields[y], "mobile")) 04226 map->options |= DUNDI_FLAG_MOBILE; 04227 else if (!strcasecmp(fields[y], "nopartial")) 04228 map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL; 04229 else 04230 ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]); 04231 } 04232 } else 04233 ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x); 04234 }
| static void build_peer | ( | dundi_eid * | eid, | |
| struct ast_variable * | v, | |||
| int * | globalpcmode | |||
| ) | [static] |
Definition at line 4318 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.
04319 { 04320 struct dundi_peer *peer; 04321 struct ast_hostent he; 04322 struct hostent *hp; 04323 dundi_eid testeid; 04324 int needregister=0; 04325 char eid_str[20]; 04326 04327 AST_LIST_LOCK(&peers); 04328 AST_LIST_TRAVERSE(&peers, peer, list) { 04329 if (!ast_eid_cmp(&peer->eid, eid)) { 04330 break; 04331 } 04332 } 04333 if (!peer) { 04334 /* Add us into the list */ 04335 if (!(peer = ast_calloc(1, sizeof(*peer)))) { 04336 AST_LIST_UNLOCK(&peers); 04337 return; 04338 } 04339 peer->registerid = -1; 04340 peer->registerexpire = -1; 04341 peer->qualifyid = -1; 04342 peer->addr.sin_family = AF_INET; 04343 peer->addr.sin_port = htons(DUNDI_PORT); 04344 populate_addr(peer, eid); 04345 AST_LIST_INSERT_HEAD(&peers, peer, list); 04346 } 04347 peer->dead = 0; 04348 peer->eid = *eid; 04349 peer->us_eid = global_eid; 04350 destroy_permissions(&peer->permit); 04351 destroy_permissions(&peer->include); 04352 AST_SCHED_DEL(sched, peer->registerid); 04353 for (; v; v = v->next) { 04354 if (!strcasecmp(v->name, "inkey")) { 04355 ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey)); 04356 } else if (!strcasecmp(v->name, "outkey")) { 04357 ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey)); 04358 } else if (!strcasecmp(v->name, "host")) { 04359 if (!strcasecmp(v->value, "dynamic")) { 04360 peer->dynamic = 1; 04361 } else { 04362 hp = ast_gethostbyname(v->value, &he); 04363 if (hp) { 04364 memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); 04365 peer->dynamic = 0; 04366 } else { 04367 ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); 04368 peer->dead = 1; 04369 } 04370 } 04371 } else if (!strcasecmp(v->name, "ustothem")) { 04372 if (!ast_str_to_eid(&testeid, v->value)) 04373 peer->us_eid = testeid; 04374 else 04375 ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno); 04376 } else if (!strcasecmp(v->name, "include")) { 04377 append_permission(&peer->include, v->value, 1); 04378 } else if (!strcasecmp(v->name, "permit")) { 04379 append_permission(&peer->permit, v->value, 1); 04380 } else if (!strcasecmp(v->name, "noinclude")) { 04381 append_permission(&peer->include, v->value, 0); 04382 } else if (!strcasecmp(v->name, "deny")) { 04383 append_permission(&peer->permit, v->value, 0); 04384 } else if (!strcasecmp(v->name, "register")) { 04385 needregister = ast_true(v->value); 04386 } else if (!strcasecmp(v->name, "order")) { 04387 if (!strcasecmp(v->value, "primary")) 04388 peer->order = 0; 04389 else if (!strcasecmp(v->value, "secondary")) 04390 peer->order = 1; 04391 else if (!strcasecmp(v->value, "tertiary")) 04392 peer->order = 2; 04393 else if (!strcasecmp(v->value, "quartiary")) 04394 peer->order = 3; 04395 else { 04396 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); 04397 } 04398 } else if (!strcasecmp(v->name, "qualify")) { 04399 if (!strcasecmp(v->value, "no")) { 04400 peer->maxms = 0; 04401 } else if (!strcasecmp(v->value, "yes")) { 04402 peer->maxms = DEFAULT_MAXMS; 04403 } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) { 04404 ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", 04405 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno); 04406 peer->maxms = 0; 04407 } 04408 } else if (!strcasecmp(v->name, "model")) { 04409 if (!strcasecmp(v->value, "inbound")) 04410 peer->model = DUNDI_MODEL_INBOUND; 04411 else if (!strcasecmp(v->value, "outbound")) 04412 peer->model = DUNDI_MODEL_OUTBOUND; 04413 else if (!strcasecmp(v->value, "symmetric")) 04414 peer->model = DUNDI_MODEL_SYMMETRIC; 04415 else if (!strcasecmp(v->value, "none")) 04416 peer->model = 0; 04417 else { 04418 ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 04419 v->value, v->lineno); 04420 } 04421 } else if (!strcasecmp(v->name, "precache")) { 04422 if (!strcasecmp(v->value, "inbound")) 04423 peer->pcmodel = DUNDI_MODEL_INBOUND; 04424 else if (!strcasecmp(v->value, "outbound")) 04425 peer->pcmodel = DUNDI_MODEL_OUTBOUND; 04426 else if (!strcasecmp(v->value, "symmetric")) 04427 peer->pcmodel = DUNDI_MODEL_SYMMETRIC; 04428 else if (!strcasecmp(v->value, "none")) 04429 peer->pcmodel = 0; 04430 else { 04431 ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", 04432 v->value, v->lineno); 04433 } 04434 } 04435 } 04436 (*globalpcmode) |= peer->pcmodel; 04437 if (!peer->model && !peer->pcmodel) { 04438 ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", 04439 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04440 peer->dead = 1; 04441 } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { 04442 ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", 04443 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04444 peer->dead = 1; 04445 } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) { 04446 ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", 04447 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04448 peer->dead = 1; 04449 } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) { 04450 ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", 04451 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04452 } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { 04453 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", 04454 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 04455 } else { 04456 if (needregister) { 04457 peer->registerid = ast_sched_add(sched, 2000, do_register, peer); 04458 } 04459 qualify_peer(peer, 1); 04460 } 04461 AST_LIST_UNLOCK(&peers); 04462 }
| static void build_secret | ( | char * | secret, | |
| int | seclen | |||
| ) | [static] |
Definition at line 2006 of file pbx_dundi.c.
References ast_base64encode(), build_iv(), and s.
Referenced by check_password(), and load_password().
02007 { 02008 unsigned char tmp[16]; 02009 char *s; 02010 build_iv(tmp); 02011 secret[0] = '\0'; 02012 ast_base64encode(secret, tmp, sizeof(tmp), seclen); 02013 /* Eliminate potential bad characters */ 02014 while((s = strchr(secret, ';'))) *s = '+'; 02015 while((s = strchr(secret, '/'))) *s = '+'; 02016 while((s = strchr(secret, ':'))) *s = '+'; 02017 while((s = strchr(secret, '@'))) *s = '+'; 02018 }
| 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 3374 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().
03375 { 03376 struct dundi_peer *p; 03377 int x; 03378 int res; 03379 int pass; 03380 int allowconnect; 03381 char eid_str[20]; 03382 AST_LIST_LOCK(&peers); 03383 AST_LIST_TRAVERSE(&peers, p, list) { 03384 if (modeselect == 1) { 03385 /* Send the precache to push upstreams only! */ 03386 pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND); 03387 allowconnect = 1; 03388 } else { 03389 /* Normal lookup / EID query */ 03390 pass = has_permission(&p->include, dr->dcontext); 03391 allowconnect = p->model & DUNDI_MODEL_OUTBOUND; 03392 } 03393 if (skip) { 03394 if (!ast_eid_cmp(skip, &p->eid)) 03395 pass = 0; 03396 } 03397 if (pass) { 03398 if (p->order <= order) { 03399 /* Check order first, then check cache, regardless of 03400 omissions, this gets us more likely to not have an 03401 affected answer. */ 03402 if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) { 03403 res = 0; 03404 /* Make sure we haven't already seen it and that it won't 03405 affect our answer */ 03406 for (x=0;avoid[x];x++) { 03407 if (!ast_eid_cmp(avoid[x], &p->eid) || !ast_eid_cmp(avoid[x], &p->us_eid)) { 03408 /* If not a direct connection, it affects our answer */ 03409 if (directs && !directs[x]) 03410 ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED); 03411 break; 03412 } 03413 } 03414 /* Make sure we can ask */ 03415 if (allowconnect) { 03416 if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) { 03417 /* Check for a matching or 0 cache entry */ 03418 append_transaction(dr, p, ttl, avoid); 03419 } else { 03420 ast_debug(1, "Avoiding '%s' in transaction\n", ast_eid_to_str(eid_str, sizeof(eid_str), avoid[x])); 03421 } 03422 } 03423 } 03424 *foundcache |= res; 03425 } else if (!*skipped || (p->order < *skipped)) 03426 *skipped = p->order; 03427 } 03428 } 03429 AST_LIST_UNLOCK(&peers); 03430 }
| static int cache_lookup | ( | struct dundi_request * | req, | |
| dundi_eid * | peer_eid, | |||
| uint32_t | crc32, | |||
| int * | lowexpiration | |||
| ) | [static] |
Definition at line 1143 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().
01144 { 01145 char key[256]; 01146 char eid_str[20]; 01147 char eidroot_str[20]; 01148 time_t now; 01149 int res=0; 01150 int res2=0; 01151 char eid_str_full[20]; 01152 char tmp[256]=""; 01153 int x; 01154 01155 time(&now); 01156 dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid); 01157 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 01158 ast_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid); 01159 snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, crc32); 01160 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01161 snprintf(key, sizeof(key), "%s/%s/%s/e%08x", eid_str, req->number, req->dcontext, 0); 01162 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01163 snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str); 01164 res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01165 x = 0; 01166 if (!req->respcount) { 01167 while(!res2) { 01168 /* Look and see if we have a hint that would preclude us from looking at this 01169 peer for this number. */ 01170 if (!(tmp[x] = req->number[x])) 01171 break; 01172 x++; 01173 /* Check for hints */ 01174 snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, crc32); 01175 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01176 snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08x", eid_str, tmp, req->dcontext, 0); 01177 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01178 snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str); 01179 res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); 01180 if (res2) { 01181 if (strlen(tmp) > strlen(req->hmd->exten)) { 01182 /* Update meta data if appropriate */ 01183 ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten)); 01184 } 01185 } 01186 } 01187 res |= res2; 01188 } 01189 01190 return res; 01191 }
| static int cache_lookup_internal | ( | time_t | now, | |
| struct dundi_request * | req, | |||
| char * | key, | |||
| char * | eid_str_full, | |||
| int * | lowexpiration | |||
| ) | [static] |
Definition at line 1071 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().
01072 { 01073 char data[1024]; 01074 char *ptr, *term, *src; 01075 int tech; 01076 struct ast_flags flags; 01077 int weight; 01078 int length; 01079 int z; 01080 char fs[256]; 01081 01082 /* Build request string */ 01083 if (!ast_db_get("dundi/cache", key, data, sizeof(data))) { 01084 time_t timeout; 01085 ptr = data; 01086 if (!ast_get_time_t(ptr, &timeout, 0, &length)) { 01087 int expiration = timeout - now; 01088 if (expiration > 0) { 01089 ast_debug(1, "Found cache expiring in %d seconds!\n", expiration); 01090 ptr += length + 1; 01091 while((sscanf(ptr, "%30d/%30d/%30d/%n", &(flags.flags), &weight, &tech, &length) == 3)) { 01092 ptr += length; 01093 term = strchr(ptr, '|'); 01094 if (term) { 01095 *term = '\0'; 01096 src = strrchr(ptr, '/'); 01097 if (src) { 01098 *src = '\0'; 01099 src++; 01100 } else 01101 src = ""; 01102 ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", 01103 tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full); 01104 /* Make sure it's not already there */ 01105 for (z=0;z<req->respcount;z++) { 01106 if ((req->dr[z].techint == tech) && 01107 !strcmp(req->dr[z].dest, ptr)) 01108 break; 01109 } 01110 if (z == req->respcount) { 01111 /* Copy into parent responses */ 01112 ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL); 01113 req->dr[req->respcount].weight = weight; 01114 req->dr[req->respcount].techint = tech; 01115 req->dr[req->respcount].expiration = expiration; 01116 dundi_str_short_to_eid(&req->dr[req->respcount].eid, src); 01117 ast_eid_to_str(req->dr[req->respcount].eid_str, 01118 sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid); 01119 ast_copy_string(req->dr[req->respcount].dest, ptr, 01120 sizeof(req->dr[req->respcount].dest)); 01121 ast_copy_string(req->dr[req->respcount].tech, tech2str(tech), 01122 sizeof(req->dr[req->respcount].tech)); 01123 req->respcount++; 01124 ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK); 01125 } else if (req->dr[z].weight > weight) 01126 req->dr[z].weight = weight; 01127 ptr = term + 1; 01128 } 01129 } 01130 /* We found *something* cached */ 01131 if (expiration < *lowexpiration) 01132 *lowexpiration = expiration; 01133 return 1; 01134 } else 01135 ast_db_del("dundi/cache", key); 01136 } else 01137 ast_db_del("dundi/cache", key); 01138 } 01139 01140 return 0; 01141 }
| static int cache_save | ( | dundi_eid * | eidpeer, | |
| struct dundi_request * | req, | |||
| int | start, | |||
| int | unaffected, | |||
| int | expiration, | |||
| int | push | |||
| ) | [static] |
Definition at line 800 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().
00801 { 00802 int x; 00803 char key1[256]; 00804 char key2[256]; 00805 char data[1024]; 00806 char eidpeer_str[20]; 00807 char eidroot_str[20]; 00808 time_t timeout; 00809 00810 if (expiration < 1) 00811 expiration = dundi_cache_time; 00812 00813 /* Keep pushes a little longer, cut pulls a little short */ 00814 if (push) 00815 expiration += 10; 00816 else 00817 expiration -= 10; 00818 if (expiration < 1) 00819 expiration = 1; 00820 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); 00821 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 00822 snprintf(key1, sizeof(key1), "%s/%s/%s/e%08x", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32); 00823 snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str); 00824 /* Build request string */ 00825 time(&timeout); 00826 timeout += expiration; 00827 snprintf(data, sizeof(data), "%ld|", (long)(timeout)); 00828 for (x=start;x<req->respcount;x++) { 00829 /* Skip anything with an illegal pipe in it */ 00830 if (strchr(req->dr[x].dest, '|')) 00831 continue; 00832 snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", 00833 req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, 00834 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid)); 00835 } 00836 ast_db_put("dundi/cache", key1, data); 00837 ast_db_put("dundi/cache", key2, data); 00838 return 0; 00839 }
| static int cache_save_hint | ( | dundi_eid * | eidpeer, | |
| struct dundi_request * | req, | |||
| struct dundi_hint * | hint, | |||
| int | expiration | |||
| ) | [static] |
Definition at line 765 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().
00766 { 00767 int unaffected; 00768 char key1[256]; 00769 char key2[256]; 00770 char eidpeer_str[20]; 00771 char eidroot_str[20]; 00772 char data[80]; 00773 time_t timeout; 00774 00775 if (expiration < 0) 00776 expiration = dundi_cache_time; 00777 00778 /* Only cache hint if "don't ask" is there... */ 00779 if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK))) 00780 return 0; 00781 00782 unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED)); 00783 00784 dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); 00785 dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); 00786 snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08x", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32); 00787 snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str); 00788 00789 time(&timeout); 00790 timeout += expiration; 00791 snprintf(data, sizeof(data), "%ld|", (long)(timeout)); 00792 00793 ast_db_put("dundi/cache", key1, data); 00794 ast_debug(1, "Caching hint at '%s'\n", key1); 00795 ast_db_put("dundi/cache", key2, data); 00796 ast_debug(1, "Caching hint at '%s'\n", key2); 00797 return 0; 00798 }
| static void cancel_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3348 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().
03349 { 03350 struct dundi_transaction *trans; 03351 03352 AST_LIST_LOCK(&peers); 03353 while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) { 03354 /* Orphan transaction from request */ 03355 trans->parent = NULL; 03356 /* Send final cancel */ 03357 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 03358 } 03359 AST_LIST_UNLOCK(&peers); 03360 }
| static int check_key | ( | struct dundi_peer * | peer, | |
| unsigned char * | newkey, | |||
| unsigned char * | newsig, | |||
| uint32_t | keycrc32 | |||
| ) | [static] |
Definition at line 1394 of file pbx_dundi.c.
References ast_aes_decrypt_key, ast_aes_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().
01395 { 01396 unsigned char dst[128]; 01397 int res; 01398 struct ast_key *key, *skey; 01399 char eid_str[20]; 01400 ast_debug(1, "Expected '%08x' got '%08x'\n", peer->them_keycrc32, keycrc32); 01401 if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) { 01402 /* A match */ 01403 return 1; 01404 } else if (!newkey || !newsig) 01405 return 0; 01406 if (!memcmp(peer->rxenckey, newkey, 128) && 01407 !memcmp(peer->rxenckey + 128, newsig, 128)) { 01408 /* By definition, a match */ 01409 return 1; 01410 } 01411 /* Decrypt key */ 01412 key = ast_key_get(peer->outkey, AST_KEY_PRIVATE); 01413 if (!key) { 01414 ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n", 01415 peer->outkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01416 return -1; 01417 } 01418 01419 skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC); 01420 if (!skey) { 01421 ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n", 01422 peer->inkey, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01423 return -1; 01424 } 01425 01426 /* First check signature */ 01427 res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig); 01428 if (res) 01429 return 0; 01430 01431 res = ast_decrypt_bin(dst, newkey, sizeof(dst), key); 01432 if (res != 16) { 01433 if (res >= 0) 01434 ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res); 01435 return 0; 01436 } 01437 /* Decrypted, passes signature */ 01438 ast_debug(1, "Wow, new key combo passed signature and decrypt!\n"); 01439 memcpy(peer->rxenckey, newkey, 128); 01440 memcpy(peer->rxenckey + 128, newsig, 128); 01441 peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128); 01442 ast_aes_decrypt_key(dst, &peer->them_dcx); 01443 ast_aes_encrypt_key(dst, &peer->them_ecx); 01444 return 1; 01445 }
| static void check_password | ( | void | ) | [static] |
Definition at line 2073 of file pbx_dundi.c.
References ast_copy_string(), build_secret(), and save_secret().
02074 { 02075 char oldsecret[80]; 02076 time_t now; 02077 02078 time(&now); 02079 #if 0 02080 printf("%ld/%ld\n", now, rotatetime); 02081 #endif 02082 if ((now - rotatetime) >= 0) { 02083 /* Time to rotate keys */ 02084 ast_copy_string(oldsecret, cursecret, sizeof(oldsecret)); 02085 build_secret(cursecret, sizeof(cursecret)); 02086 save_secret(cursecret, oldsecret); 02087 } 02088 }
| static int check_request | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3469 of file pbx_dundi.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.
Referenced by dundi_lookup_internal().
03470 { 03471 struct dundi_request *cur; 03472 03473 AST_LIST_LOCK(&peers); 03474 AST_LIST_TRAVERSE(&requests, cur, list) { 03475 if (cur == dr) 03476 break; 03477 } 03478 AST_LIST_UNLOCK(&peers); 03479 03480 return cur ? 1 : 0; 03481 }
| static char* complete_peer_helper | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state, | |||
| int | rpos | |||
| ) | [static] |
Definition at line 2307 of file pbx_dundi.c.
References ast_eid_to_str(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, dundi_peer::eid, len(), and s.
Referenced by dundi_show_peer().
02308 { 02309 int which=0, len; 02310 char *ret = NULL; 02311 struct dundi_peer *p; 02312 char eid_str[20]; 02313 02314 if (pos != rpos) 02315 return NULL; 02316 AST_LIST_LOCK(&peers); 02317 len = strlen(word); 02318 AST_LIST_TRAVERSE(&peers, p, list) { 02319 const char *s = ast_eid_to_str(eid_str, sizeof(eid_str), &p->eid); 02320 if (!strncasecmp(word, s, len) && ++which > state) { 02321 ret = ast_strdup(s); 02322 break; 02323 } 02324 } 02325 AST_LIST_UNLOCK(&peers); 02326 return ret; 02327 }
| static struct dundi_transaction * create_transaction | ( | struct dundi_peer * | p | ) | [static, read] |
Definition at line 2824 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().
02825 { 02826 struct dundi_transaction *trans; 02827 int tid; 02828 02829 /* Don't allow creation of transactions to non-registered peers */ 02830 if (p && !p->addr.sin_addr.s_addr) 02831 return NULL; 02832 tid = get_trans_id(); 02833 if (tid < 1) 02834 return NULL; 02835 if (!(trans = ast_calloc(1, sizeof(*trans)))) 02836 return NULL; 02837 02838 if (global_storehistory) { 02839 trans->start = ast_tvnow(); 02840 ast_set_flag(trans, FLAG_STOREHIST); 02841 } 02842 trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; 02843 trans->autokillid = -1; 02844 if (p) { 02845 apply_peer(trans, p); 02846 if (!p->sentfullkey) 02847 ast_set_flag(trans, FLAG_SENDFULLKEY); 02848 } 02849 trans->strans = tid; 02850 AST_LIST_INSERT_HEAD(&alltrans, trans, all); 02851 02852 return trans; 02853 }
| static int decrypt_memcpy | ( | unsigned char * | dst, | |
| unsigned char * | src, | |||
| int | len, | |||
| unsigned char * | iv, | |||
| ast_aes_decrypt_key * | dcx | |||
| ) | [static] |
Definition at line 1286 of file pbx_dundi.c.
References ast_aes_decrypt.
Referenced by dundi_decrypt().
01287 { 01288 unsigned char lastblock[16]; 01289 int x; 01290 memcpy(lastblock, iv, sizeof(lastblock)); 01291 while(len > 0) { 01292 ast_aes_decrypt(src, dst, dcx); 01293 for (x=0;x<16;x++) 01294 dst[x] ^= lastblock[x]; 01295 memcpy(lastblock, src, sizeof(lastblock)); 01296 dst += 16; 01297 src += 16; 01298 len -= 16; 01299 } 01300 return 0; 01301 }
| static void deep_copy_peer | ( | struct dundi_peer * | peer_dst, | |
| const struct dundi_peer * | peer_src | |||
| ) | [static] |
Definition at line 1447 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().
01448 { 01449 struct permission *cur, *perm; 01450 01451 memcpy(peer_dst, peer_src, sizeof(*peer_dst)); 01452 01453 memset(&peer_dst->permit, 0, sizeof(peer_dst->permit)); 01454 memset(&peer_dst->include, 0, sizeof(peer_dst->permit)); 01455 01456 AST_LIST_TRAVERSE(&peer_src->permit, cur, list) { 01457 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1))) 01458 continue; 01459 01460 perm->allow = cur->allow; 01461 strcpy(perm->name, cur->name); 01462 01463 AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list); 01464 } 01465 01466 AST_LIST_TRAVERSE(&peer_src->include, cur, list) { 01467 if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1))) 01468 continue; 01469 01470 perm->allow = cur->allow; 01471 strcpy(perm->name, cur->name); 01472 01473 AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list); 01474 } 01475 }
| static void destroy_map | ( | struct dundi_mapping * | map | ) | [static] |
Definition at line 4111 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 2871 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().
02872 { 02873 if (pack->parent) 02874 AST_LIST_REMOVE(&pack->parent->packets, pack, list); 02875 AST_SCHED_DEL(sched, pack->retransid); 02876 if (needfree) 02877 ast_free(pack); 02878 }
| static void destroy_packets | ( | struct packetlist * | p | ) | [static] |
Definition at line 1905 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().
01906 { 01907 struct dundi_packet *pack; 01908 01909 while ((pack = AST_LIST_REMOVE_HEAD(p, list))) { 01910 AST_SCHED_DEL(sched, pack->retransid); 01911 ast_free(pack); 01912 } 01913 }
| static void destroy_peer | ( | struct dundi_peer * | peer | ) | [static] |
Definition at line 4100 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().
04101 { 04102 AST_SCHED_DEL(sched, peer->registerid); 04103 if (peer->regtrans) 04104 destroy_trans(peer->regtrans, 0); 04105 AST_SCHED_DEL(sched, peer->qualifyid); 04106 destroy_permissions(&peer->permit); 04107 destroy_permissions(&peer->include); 04108 ast_free(peer); 04109 }
| static void destroy_permissions | ( | struct permissionlist * | permlist | ) | [static] |
Definition at line 4092 of file pbx_dundi.c.
References ast_free, and AST_LIST_REMOVE_HEAD.
Referenced by build_peer(), and destroy_peer().
04093 { 04094 struct permission *perm; 04095 04096 while ((perm = AST_LIST_REMOVE_HEAD(permlist, list))) 04097 ast_free(perm); 04098 }
| static void destroy_trans | ( | struct dundi_transaction * | trans, | |
| int | fromtimeout | |||
| ) | [static] |
Definition at line 2880 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().
02881 { 02882 struct dundi_peer *peer; 02883 int ms; 02884 int x; 02885 int cnt; 02886 char eid_str[20]; 02887 if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) { 02888 AST_LIST_TRAVERSE(&peers, peer, list) { 02889 if (peer->regtrans == trans) 02890 peer->regtrans = NULL; 02891 if (peer->qualtrans == trans) { 02892 if (fromtimeout) { 02893 if (peer->lastms > -1) 02894 ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02895 peer->lastms = -1; 02896 } else { 02897 ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx); 02898 if (ms < 1) 02899 ms = 1; 02900 if (ms < peer->maxms) { 02901 if ((peer->lastms >= peer->maxms) || (peer->lastms < 0)) 02902 ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02903 } else if (peer->lastms < peer->maxms) { 02904 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); 02905 } 02906 peer->lastms = ms; 02907 } 02908 peer->qualtrans = NULL; 02909 } 02910 if (ast_test_flag(trans, FLAG_STOREHIST)) { 02911 if (trans->parent && !ast_strlen_zero(trans->parent->number)) { 02912 if (!ast_eid_cmp(&trans->them_eid, &peer->eid)) { 02913 peer->avgms = 0; 02914 cnt = 0; 02915 if (peer->lookups[DUNDI_TIMING_HISTORY-1]) 02916 ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]); 02917 for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) { 02918 peer->lookuptimes[x] = peer->lookuptimes[x-1]; 02919 peer->lookups[x] = peer->lookups[x-1]; 02920 if (peer->lookups[x]) { 02921 peer->avgms += peer->lookuptimes[x]; 02922 cnt++; 02923 } 02924 } 02925 peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start); 02926 peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2); 02927 if (peer->lookups[0]) { 02928 sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext); 02929 peer->avgms += peer->lookuptimes[0]; 02930 cnt++; 02931 } 02932 if (cnt) 02933 peer->avgms /= cnt; 02934 } 02935 } 02936 } 02937 } 02938 } 02939 if (trans->parent) { 02940 /* Unlink from parent if appropriate */ 02941 AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist); 02942 if (AST_LIST_EMPTY(&trans->parent->trans)) { 02943 /* Wake up sleeper */ 02944 if (trans->parent->pfds[1] > -1) { 02945 if (write(trans->parent->pfds[1], "killa!", 6) < 0) { 02946 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 02947 } 02948 } 02949 } 02950 } 02951 /* Unlink from all trans */ 02952 AST_LIST_REMOVE(&alltrans, trans, all); 02953 destroy_packets(&trans->packets); 02954 destroy_packets(&trans->lasttrans); 02955 AST_SCHED_DEL(sched, trans->autokillid); 02956 if (trans->thread) { 02957 /* If used by a thread, mark as dead and be done */ 02958 ast_set_flag(trans, FLAG_DEAD); 02959 } else 02960 ast_free(trans); 02961 }
| static int discover_transactions | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3202 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().
03203 { 03204 struct dundi_transaction *trans; 03205 AST_LIST_LOCK(&peers); 03206 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03207 dundi_discover(trans); 03208 } 03209 AST_LIST_UNLOCK(&peers); 03210 return 0; 03211 }
| static int do_autokill | ( | const void * | data | ) | [static] |
Definition at line 3057 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().
03058 { 03059 struct dundi_transaction *trans = (struct dundi_transaction *)data; 03060 char eid_str[20]; 03061 ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", 03062 ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); 03063 trans->autokillid = -1; 03064 destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */ 03065 return 0; 03066 }
| static int do_qualify | ( | const void * | data | ) | [static] |
Definition at line 4263 of file pbx_dundi.c.
References qualify_peer(), and dundi_peer::qualifyid.
Referenced by qualify_peer().
04264 { 04265 struct dundi_peer *peer = (struct dundi_peer *)data; 04266 peer->qualifyid = -1; 04267 qualify_peer(peer, 0); 04268 return 0; 04269 }
| static int do_register | ( | const void * | data | ) | [static] |
Definition at line 4237 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().
04238 { 04239 struct dundi_ie_data ied; 04240 struct dundi_peer *peer = (struct dundi_peer *)data; 04241 char eid_str[20]; 04242 char eid_str2[20]; 04243 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)); 04244 peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data); 04245 /* Destroy old transaction if there is one */ 04246 if (peer->regtrans) 04247 destroy_trans(peer->regtrans, 0); 04248 peer->regtrans = create_transaction(peer); 04249 if (peer->regtrans) { 04250 ast_set_flag(peer->regtrans, FLAG_ISREG); 04251 memset(&ied, 0, sizeof(ied)); 04252 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 04253 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid); 04254 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration); 04255 dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied); 04256 04257 } else 04258 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)); 04259 04260 return 0; 04261 }
| static int do_register_expire | ( | const void * | data | ) | [static] |
Definition at line 1220 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().
01221 { 01222 struct dundi_peer *peer = (struct dundi_peer *)data; 01223 char eid_str[20]; 01224 ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 01225 peer->registerexpire = -1; 01226 peer->lastms = 0; 01227 memset(&peer->addr, 0, sizeof(peer->addr)); 01228 return 0; 01229 }
| static void drds_destroy | ( | struct dundi_result_datastore * | drds | ) | [static] |
Definition at line 3888 of file pbx_dundi.c.
References ast_free.
Referenced by drds_destroy_cb(), and dundi_query_read().
03889 { 03890 ast_free(drds); 03891 }
| static void drds_destroy_cb | ( | void * | data | ) | [static] |
Definition at line 3893 of file pbx_dundi.c.
References drds_destroy().
03894 { 03895 struct dundi_result_datastore *drds = data; 03896 drds_destroy(drds); 03897 }
| static int dundi_ack | ( | struct dundi_transaction * | trans, | |
| int | final | |||
| ) | [static] |
Definition at line 363 of file pbx_dundi.c.
References DUNDI_COMMAND_ACK, and dundi_send().
Referenced by handle_command_response(), and handle_frame().
00364 { 00365 return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL); 00366 }
| static int dundi_answer_entity | ( | struct dundi_transaction * | trans, | |
| struct dundi_ies * | ies, | |||
| char * | ccontext | |||
| ) | [static] |
Definition at line 710 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, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.
Referenced by handle_command_response().
00711 { 00712 struct dundi_query_state *st; 00713 int totallen; 00714 int x; 00715 int skipfirst=0; 00716 char eid_str[20]; 00717 char *s; 00718 pthread_t lookupthread; 00719 00720 if (ies->eidcount > 1) { 00721 /* Since it is a requirement that the first EID is the authenticating host 00722 and the last EID is the root, it is permissible that the first and last EID 00723 could be the same. In that case, we should go ahead copy only the "root" section 00724 since we will not need it for authentication. */ 00725 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 00726 skipfirst = 1; 00727 } 00728 totallen = sizeof(struct dundi_query_state); 00729 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 00730 st = ast_calloc(1, totallen); 00731 if (st) { 00732 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); 00733 memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid)); 00734 st->trans = trans; 00735 st->ttl = ies->ttl - 1; 00736 if (st->ttl < 0) 00737 st->ttl = 0; 00738 s = st->fluffy; 00739 for (x=skipfirst;ies->eids[x];x++) { 00740 st->eids[x-skipfirst] = (dundi_eid *)s; 00741 *st->eids[x-skipfirst] = *ies->eids[x]; 00742 s += sizeof(dundi_eid); 00743 } 00744 ast_debug(1, "Answering EID query for '%s@%s'!\n", ast_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context); 00745 00746 trans->thread = 1; 00747 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) { 00748 struct dundi_ie_data ied = { 0, }; 00749 trans->thread = 0; 00750 ast_log(LOG_WARNING, "Unable to create thread!\n"); 00751 ast_free(st); 00752 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 00753 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00754 return -1; 00755 } 00756 } else { 00757 struct dundi_ie_data ied = { 0, }; 00758 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 00759 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00760 return -1; 00761 } 00762 return 0; 00763 }
| static int dundi_answer_query | ( | struct dundi_transaction * | trans, | |
| struct dundi_ies * | ies, | |||
| char * | ccontext | |||
| ) | [static] |
Definition at line 988 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, s, dundi_transaction::thread, dundi_query_state::trans, dundi_ies::ttl, and dundi_query_state::ttl.
Referenced by handle_command_response().
00989 { 00990 struct dundi_query_state *st; 00991 int totallen; 00992 int x; 00993 struct dundi_ie_data ied; 00994 char *s; 00995 struct dundi_mapping *cur; 00996 int mapcount = 0; 00997 int skipfirst = 0; 00998 00999 pthread_t lookupthread; 01000 totallen = sizeof(struct dundi_query_state); 01001 /* Count matching map entries */ 01002 AST_LIST_TRAVERSE(&mappings, cur, list) { 01003 if (!strcasecmp(cur->dcontext, ccontext)) 01004 mapcount++; 01005 } 01006 /* If no maps, return -1 immediately */ 01007 if (!mapcount) 01008 return -1; 01009 01010 if (ies->eidcount > 1) { 01011 /* Since it is a requirement that the first EID is the authenticating host 01012 and the last EID is the root, it is permissible that the first and last EID 01013 could be the same. In that case, we should go ahead copy only the "root" section 01014 since we will not need it for authentication. */ 01015 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 01016 skipfirst = 1; 01017 } 01018 01019 totallen += mapcount * sizeof(struct dundi_mapping); 01020 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 01021 st = ast_calloc(1, totallen); 01022 if (st) { 01023 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); 01024 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); 01025 st->trans = trans; 01026 st->ttl = ies->ttl - 1; 01027 st->nocache = ies->cbypass; 01028 if (st->ttl < 0) 01029 st->ttl = 0; 01030 s = st->fluffy; 01031 for (x=skipfirst;ies->eids[x];x++) { 01032 st->eids[x-skipfirst] = (dundi_eid *)s; 01033 *st->eids[x-skipfirst] = *ies->eids[x]; 01034 st->directs[x-skipfirst] = ies->eid_direct[x]; 01035 s += sizeof(dundi_eid); 01036 } 01037 /* Append mappings */ 01038 x = 0; 01039 st->maps = (struct dundi_mapping *)s; 01040 AST_LIST_TRAVERSE(&mappings, cur, list) { 01041 if (!strcasecmp(cur->dcontext, ccontext)) { 01042 if (x < mapcount) { 01043 st->maps[x] = *cur; 01044 st->maps[x].list.next = NULL; 01045 x++; 01046 } 01047 } 01048 } 01049 st->nummaps = mapcount; 01050 ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context); 01051 trans->thread = 1; 01052 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) { 01053 trans->thread = 0; 01054 ast_log(LOG_WARNING, "Unable to create thread!\n"); 01055 ast_free(st); 01056 memset(&ied, 0, sizeof(ied)); 01057 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 01058 dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 01059 return -1; 01060 } 01061 } else { 01062 ast_log(LOG_WARNING, "Out of memory!\n"); 01063 memset(&ied, 0, sizeof(ied)); 01064 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 01065 dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 01066 return -1; 01067 } 01068 return 0; 01069 }
| 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 4508 of file pbx_dundi.c.
References DUNDI_FLAG_CANMATCH, and dundi_helper().
04509 { 04510 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH); 04511 }
| static void dundi_debug_output | ( | const char * | data | ) | [static] |
Definition at line 270 of file pbx_dundi.c.
References ast_verbose.
Referenced by load_module().
00271 { 00272 if (dundidebug) 00273 ast_verbose("%s", data); 00274 }
| 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 1303 of file pbx_dundi.c.
References ast_debug, dundi_transaction::dcx, decrypt_memcpy(), dundi_encblock::encdata, and dundi_encblock::iv.
Referenced by handle_command_response().
01304 { 01305 int space = *dstlen; 01306 unsigned long bytes; 01307 struct dundi_hdr *h; 01308 unsigned char *decrypt_space; 01309 decrypt_space = alloca(srclen); 01310 if (!decrypt_space) 01311 return NULL; 01312 decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx); 01313 /* Setup header */ 01314 h = (struct dundi_hdr *)dst; 01315 *h = *ohdr; 01316 bytes = space - 6; 01317 if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) { 01318 ast_debug(1, "Ouch, uncompress failed :(\n"); 01319 return NULL; 01320 } 01321 /* Update length */ 01322 *dstlen = bytes + 6; 01323 /* Return new header */ 01324 return h; 01325 }
| static int dundi_discover | ( | struct dundi_transaction * | trans | ) | [static] |
Definition at line 3090 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().
03091 { 03092 struct dundi_ie_data ied; 03093 int x; 03094 if (!trans->parent) { 03095 ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); 03096 return -1; 03097 } 03098 memset(&ied, 0, sizeof(ied)); 03099 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03100 if (!dundi_eid_zero(&trans->us_eid)) 03101 dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid); 03102 for (x=0;x<trans->eidcount;x++) 03103 dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid); 03104 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); 03105 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03106 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03107 if (trans->parent->cbypass) 03108 dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS); 03109 if (trans->autokilltimeout) 03110 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03111 return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied); 03112 }
| static char* dundi_do_lookup | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2346 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.
02347 { 02348 int res; 02349 char tmp[256]; 02350 char fs[80] = ""; 02351 char *context; 02352 int x; 02353 int bypass = 0; 02354 struct dundi_result dr[MAX_RESULTS]; 02355 struct timeval start; 02356 switch (cmd) { 02357 case CLI_INIT: 02358 e->command = "dundi lookup"; 02359 e->usage = 02360 "Usage: dundi lookup <number>[@context] [bypass]\n" 02361 " Lookup the given number within the given DUNDi context\n" 02362 "(or e164 if none is specified). Bypasses cache if 'bypass'\n" 02363 "keyword is specified.\n"; 02364 return NULL; 02365 case CLI_GENERATE: 02366 return NULL; 02367 } 02368 02369 if ((a->argc < 3) || (a->argc > 4)) 02370 return CLI_SHOWUSAGE; 02371 if (a->argc > 3) { 02372 if (!strcasecmp(a->argv[3], "bypass")) 02373 bypass=1; 02374 else 02375 return CLI_SHOWUSAGE; 02376 } 02377 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02378 context = strchr(tmp, '@'); 02379 if (context) { 02380 *context = '\0'; 02381 context++; 02382 } 02383 start = ast_tvnow(); 02384 res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass); 02385 02386 if (res < 0) 02387 ast_cli(a->fd, "DUNDi lookup returned error.\n"); 02388 else if (!res) 02389 ast_cli(a->fd, "DUNDi lookup returned no results.\n"); 02390 else 02391 sort_results(dr, res); 02392 for (x=0;x<res;x++) { 02393 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)); 02394 ast_cli(a->fd, " from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration); 02395 } 02396 ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start)); 02397 return CLI_SUCCESS; 02398 }
| static char* dundi_do_precache | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2400 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.
02401 { 02402 int res; 02403 char tmp[256]; 02404 char *context; 02405 struct timeval start; 02406 switch (cmd) { 02407 case CLI_INIT: 02408 e->command = "dundi precache"; 02409 e->usage = 02410 "Usage: dundi precache <number>[@context]\n" 02411 " Lookup the given number within the given DUNDi context\n" 02412 "(or e164 if none is specified) and precaches the results to any\n" 02413 "upstream DUNDi push servers.\n"; 02414 return NULL; 02415 case CLI_GENERATE: 02416 return NULL; 02417 } 02418 if ((a->argc < 3) || (a->argc > 3)) 02419 return CLI_SHOWUSAGE; 02420 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02421 context = strchr(tmp, '@'); 02422 if (context) { 02423 *context = '\0'; 02424 context++; 02425 } 02426 start = ast_tvnow(); 02427 res = dundi_precache(context, tmp); 02428 02429 if (res < 0) 02430 ast_cli(a->fd, "DUNDi precache returned error.\n"); 02431 else if (!res) 02432 ast_cli(a->fd, "DUNDi precache returned no error.\n"); 02433 ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start)); 02434 return CLI_SUCCESS; 02435 }
| static char* dundi_do_query | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2437 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.
02438 { 02439 int res; 02440 char tmp[256]; 02441 char *context; 02442 dundi_eid eid; 02443 struct dundi_entity_info dei; 02444 switch (cmd) { 02445 case CLI_INIT: 02446 e->command = "dundi query"; 02447 e->usage = 02448 "Usage: dundi query <entity>[@context]\n" 02449 " Attempts to retrieve contact information for a specific\n" 02450 "DUNDi entity identifier (EID) within a given DUNDi context (or\n" 02451 "e164 if none is specified).\n"; 02452 return NULL; 02453 case CLI_GENERATE: 02454 return NULL; 02455 } 02456 if ((a->argc < 3) || (a->argc > 3)) 02457 return CLI_SHOWUSAGE; 02458 if (ast_str_to_eid(&eid, a->argv[2])) { 02459 ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]); 02460 return CLI_SHOWUSAGE; 02461 } 02462 ast_copy_string(tmp, a->argv[2], sizeof(tmp)); 02463 context = strchr(tmp, '@'); 02464 if (context) { 02465 *context = '\0'; 02466 context++; 02467 } 02468 res = dundi_query_eid(&dei, context, eid); 02469 if (res < 0) 02470 ast_cli(a->fd, "DUNDi Query EID returned error.\n"); 02471 else if (!res) 02472 ast_cli(a->fd, "DUNDi Query EID returned no results.\n"); 02473 else { 02474 ast_cli(a->fd, "DUNDi Query EID succeeded:\n"); 02475 ast_cli(a->fd, "Department: %s\n", dei.orgunit); 02476 ast_cli(a->fd, "Organization: %s\n", dei.org); 02477 ast_cli(a->fd, "City/Locality: %s\n", dei.locality); 02478 ast_cli(a->fd, "State/Province: %s\n", dei.stateprov); 02479 ast_cli(a->fd, "Country: %s\n", dei.country); 02480 ast_cli(a->fd, "E-mail: %s\n", dei.email); 02481 ast_cli(a->fd, "Phone: %s\n", dei.phone); 02482 ast_cli(a->fd, "IP Address: %s\n", dei.ipaddr); 02483 } 02484 return CLI_SUCCESS; 02485 }
| static int dundi_encrypt | ( | struct dundi_transaction * | trans, | |
| struct dundi_packet * | pack | |||
| ) | [static] |
Definition at line 1327 of file pbx_dundi.c.
References 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().
01328 { 01329 unsigned char *compress_space; 01330 int len; 01331 int res; 01332 unsigned long bytes; 01333 struct dundi_ie_data ied; 01334 struct dundi_peer *peer; 01335 unsigned char iv[16]; 01336 len = pack->datalen + pack->datalen / 100 + 42; 01337 compress_space = alloca(len); 01338 if (compress_space) { 01339 memset(compress_space, 0, len); 01340 /* We care about everthing save the first 6 bytes of header */ 01341 bytes = len; 01342 res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6); 01343 if (res != Z_OK) { 01344 ast_debug(1, "Ouch, compression failed!\n"); 01345 return -1; 01346 } 01347 memset(&ied, 0, sizeof(ied)); 01348 /* Say who we are */ 01349 if (!pack->h->iseqno && !pack->h->oseqno) { 01350 /* Need the key in the first copy */ 01351 if (!(peer = find_peer(&trans->them_eid))) 01352 return -1; 01353 if (update_key(peer)) 01354 return -1; 01355 if (!peer->sentfullkey) 01356 ast_set_flag(trans, FLAG_SENDFULLKEY); 01357 /* Append key data */ 01358 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 01359 if (ast_test_flag(trans, FLAG_SENDFULLKEY)) { 01360 dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); 01361 dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); 01362 } else { 01363 dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32); 01364 } 01365 /* Setup contexts */ 01366 trans->ecx = peer->us_ecx; 01367 trans->dcx = peer->us_dcx; 01368 01369 /* We've sent the full key */ 01370 peer->sentfullkey = 1; 01371 } 01372 /* Build initialization vector */ 01373 build_iv(iv); 01374 /* Add the field, rounded up to 16 bytes */ 01375 dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16); 01376 /* Copy the data */ 01377 if ((ied.pos + bytes) >= sizeof(ied.buf)) { 01378 ast_log(LOG_NOTICE, "Final packet too large!\n"); 01379 return -1; 01380 } 01381 encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx); 01382 ied.pos += ((bytes + 15) / 16) * 16; 01383 /* Reconstruct header */ 01384 pack->datalen = sizeof(struct dundi_hdr); 01385 pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT; 01386 pack->h->cmdflags = 0; 01387 memcpy(pack->h->ies, ied.buf, ied.pos); 01388 pack->datalen += ied.pos; 01389 return 0; 01390 } 01391 return -1; 01392 }
| static void dundi_error_output | ( | const char * | data | ) | [static] |
Definition at line 276 of file pbx_dundi.c.
References ast_log(), and LOG_WARNING.
Referenced by load_module().
00277 { 00278 ast_log(LOG_WARNING, "%s", data); 00279 }
| 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 4513 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().
04514 { 04515 struct dundi_result results[MAX_RESULTS]; 04516 int res; 04517 int x=0; 04518 char req[1024]; 04519 const char *dundiargs; 04520 struct ast_app *dial; 04521 04522 if (!strncasecmp(context, "macro-", 6)) { 04523 if (!chan) { 04524 ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); 04525 return -1; 04526 } 04527 /* If done as a macro, use macro extension */ 04528 if (!strcasecmp(exten, "s")) { 04529 exten = pbx_builtin_getvar_helper(chan, "ARG1"); 04530 if (ast_strlen_zero(exten)) 04531 exten = chan->macroexten; 04532 if (ast_strlen_zero(exten)) 04533 exten = chan->exten; 04534 if (ast_strlen_zero(exten)) { 04535 ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); 04536 return -1; 04537 } 04538 } 04539 if (ast_strlen_zero(data)) 04540 data = "e164"; 04541 } else { 04542 if (ast_strlen_zero(data)) 04543 data = context; 04544 } 04545 res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); 04546 if (res > 0) { 04547 sort_results(results, res); 04548 for (x=0;x<res;x++) { 04549 if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) { 04550 if (!--priority) 04551 break; 04552 } 04553 } 04554 } 04555 if (x < res) { 04556 /* Got a hit! */ 04557 dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS"); 04558 snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest, 04559 S_OR(dundiargs, "")); 04560 dial = pbx_findapp("Dial"); 04561 if (dial) 04562 res = pbx_exec(chan, dial, req); 04563 } else 04564 res = -1; 04565 return res; 04566 }
| 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 4503 of file pbx_dundi.c.
References DUNDI_FLAG_EXISTS, and dundi_helper().
04504 { 04505 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS); 04506 }
| static char* dundi_flush | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2248 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.
02249 { 02250 int stats = 0; 02251 switch (cmd) { 02252 case CLI_INIT: 02253 e->command = "dundi flush [stats]"; 02254 e->usage = 02255 "Usage: dundi flush [stats]\n" 02256 " Flushes DUNDi answer cache, used primarily for debug. If\n" 02257 "'stats' is present, clears timer statistics instead of normal\n" 02258 "operation.\n"; 02259 return NULL; 02260 case CLI_GENERATE: 02261 return NULL; 02262 } 02263 if ((a->argc < 2) || (a->argc > 3)) 02264 return CLI_SHOWUSAGE; 02265 if (a->argc > 2) { 02266 if (!strcasecmp(a->argv[2], "stats")) 02267 stats = 1; 02268 else 02269 return CLI_SHOWUSAGE; 02270 } 02271 if (stats) { 02272 /* Flush statistics */ 02273 struct dundi_peer *p; 02274 int x; 02275 AST_LIST_LOCK(&peers); 02276 AST_LIST_TRAVERSE(&peers, p, list) { 02277 for (x = 0;x < DUNDI_TIMING_HISTORY; x++) { 02278 if (p->lookups[x]) 02279 ast_free(p->lookups[x]); 02280 p->lookups[x] = NULL; 02281 p->lookuptimes[x] = 0; 02282 } 02283 p->avgms = 0; 02284 } 02285 AST_LIST_UNLOCK(&peers); 02286 } else { 02287 ast_db_deltree("dundi/cache", NULL); 02288 ast_cli(a->fd, "DUNDi Cache Flushed\n"); 02289 } 02290 return CLI_SUCCESS; 02291 }
| 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 4464 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().
04465 { 04466 struct dundi_result results[MAX_RESULTS]; 04467 int res; 04468 int x; 04469 int found = 0; 04470 if (!strncasecmp(context, "macro-", 6)) { 04471 if (!chan) { 04472 ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); 04473 return -1; 04474 } 04475 /* If done as a macro, use macro extension */ 04476 if (!strcasecmp(exten, "s")) { 04477 exten = pbx_builtin_getvar_helper(chan, "ARG1"); 04478 if (ast_strlen_zero(exten)) 04479 exten = chan->macroexten; 04480 if (ast_strlen_zero(exten)) 04481 exten = chan->exten; 04482 if (ast_strlen_zero(exten)) { 04483 ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); 04484 return -1; 04485 } 04486 } 04487 if (ast_strlen_zero(data)) 04488 data = "e164"; 04489 } else { 04490 if (ast_strlen_zero(data)) 04491 data = context; 04492 } 04493 res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); 04494 for (x=0;x<res;x++) { 04495 if (ast_test_flag(results + x, flag)) 04496 found++; 04497 } 04498 if (found >= priority) 04499 return 1; 04500 return 0; 04501 }
| static void dundi_ie_append_eid_appropriately | ( | struct dundi_ie_data * | ied, | |
| char * | context, | |||
| dundi_eid * | eid, | |||
| dundi_eid * | us | |||
| ) | [static] |
Definition at line 3068 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().
03069 { 03070 struct dundi_peer *p; 03071 if (!ast_eid_cmp(eid, us)) { 03072 dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); 03073 return; 03074 } 03075 AST_LIST_LOCK(&peers); 03076 AST_LIST_TRAVERSE(&peers, p, list) { 03077 if (!ast_eid_cmp(&p->eid, eid)) { 03078 if (has_permission(&p->include, context)) 03079 dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); 03080 else 03081 dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); 03082 break; 03083 } 03084 } 03085 if (!p) 03086 dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); 03087 AST_LIST_UNLOCK(&peers); 03088 }
| 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 3600 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().
03601 { 03602 struct dundi_hint_metadata hmd; 03603 dundi_eid *avoid[1] = { NULL, }; 03604 int direct[1] = { 0, }; 03605 int expiration = dundi_cache_time; 03606 memset(&hmd, 0, sizeof(hmd)); 03607 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 03608 return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct); 03609 }
| 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 3498 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, ast_channel::name, 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().
03499 { 03500 int res; 03501 struct dundi_request dr, *pending; 03502 dundi_eid *rooteid=NULL; 03503 int x; 03504 int ttlms; 03505 int ms; 03506 int foundcache; 03507 int skipped=0; 03508 int order=0; 03509 char eid_str[20]; 03510 struct timeval start; 03511 03512 /* Don't do anthing for a hungup channel */ 03513 if (chan && ast_check_hangup(chan)) 03514 return 0; 03515 03516 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03517 03518 for (x=0;avoid[x];x++) 03519 rooteid = avoid[x]; 03520 /* Now perform real check */ 03521 memset(&dr, 0, sizeof(dr)); 03522 if (pipe(dr.pfds)) { 03523 ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno)); 03524 return -1; 03525 } 03526 dr.dr = result; 03527 dr.hmd = hmd; 03528 dr.maxcount = maxret; 03529 dr.expiration = *expiration; 03530 dr.cbypass = cbypass; 03531 dr.crc32 = avoid_crc32(avoid); 03532 ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); 03533 ast_copy_string(dr.number, number, sizeof(dr.number)); 03534 if (rooteid) 03535 dr.root_eid = *rooteid; 03536 res = register_request(&dr, &pending); 03537 if (res) { 03538 /* Already a request */ 03539 if (rooteid && !ast_eid_cmp(&dr.root_eid, &pending->root_eid)) { 03540 /* This is on behalf of someone else. Go ahead and close this out since 03541 they'll get their answer anyway. */ 03542 ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n", 03543 dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid)); 03544 close(dr.pfds[0]); 03545 close(dr.pfds[1]); 03546 return -2; 03547 } else { 03548 /* Wait for the cache to populate */ 03549 ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n", 03550 dr.number,dr.dcontext,ast_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid)); 03551 start = ast_tvnow(); 03552 while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) { 03553 /* XXX Would be nice to have a way to poll/select here XXX */ 03554 /* XXX this is a busy wait loop!!! */ 03555 usleep(1); 03556 } 03557 /* Continue on as normal, our cache should kick in */ 03558 } 03559 } 03560 /* Create transactions */ 03561 do { 03562 order = skipped; 03563 skipped = 0; 03564 foundcache = 0; 03565 build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct); 03566 } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans)); 03567 /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't 03568 do this earlier because we didn't know if we were going to have transactions 03569 or not. */ 03570 if (!ttl) { 03571 ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); 03572 abort_request(&dr); 03573 unregister_request(&dr); 03574 close(dr.pfds[0]); 03575 close(dr.pfds[1]); 03576 return 0; 03577 } 03578 03579 /* Optimize transactions */ 03580 optimize_transactions(&dr, order); 03581 /* Actually perform transactions */ 03582 discover_transactions(&dr); 03583 /* Wait for transaction to come back */ 03584 start = ast_tvnow(); 03585 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) { 03586 ms = 100; 03587 ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); 03588 } 03589 if (chan && ast_check_hangup(chan)) 03590 ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext); 03591 cancel_request(&dr); 03592 unregister_request(&dr); 03593 res = dr.respcount; 03594 *expiration = dr.expiration; 03595 close(dr.pfds[0]); 03596 close(dr.pfds[1]); 03597 return res; 03598 }
| 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 485 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, ast_var_t::entries, 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().
00486 { 00487 struct ast_flags flags = {0}; 00488 int x; 00489 if (!ast_strlen_zero(map->lcontext)) { 00490 if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL)) 00491 ast_set_flag(&flags, DUNDI_FLAG_EXISTS); 00492 if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL)) 00493 ast_set_flag(&flags, DUNDI_FLAG_CANMATCH); 00494 if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL)) 00495 ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE); 00496 if (ast_ignore_pattern(map->lcontext, called_number)) 00497 ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT); 00498 00499 /* Clearly we can't say 'don't ask' anymore if we found anything... */ 00500 if (ast_test_flag(&flags, AST_FLAGS_ALL)) 00501 ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK); 00502 00503 if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) { 00504 /* Skip partial answers */ 00505 ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH); 00506 } 00507 if (ast_test_flag(&flags, AST_FLAGS_ALL)) { 00508 struct varshead headp; 00509 struct ast_var_t *newvariable; 00510 ast_set_flag(&flags, map->options & 0xffff); 00511 ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL); 00512 dr[anscnt].techint = map->tech; 00513 dr[anscnt].weight = get_mapping_weight(map); 00514 dr[anscnt].expiration = dundi_cache_time; 00515 ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech)); 00516 dr[anscnt].eid = *us_eid; 00517 ast_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid); 00518 if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) { 00519 AST_LIST_HEAD_INIT_NOLOCK(&headp); 00520 newvariable = ast_var_assign("NUMBER", called_number); 00521 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00522 newvariable = ast_var_assign("EID", dr[anscnt].eid_str); 00523 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00524 newvariable = ast_var_assign("SECRET", cursecret); 00525 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00526 newvariable = ast_var_assign("IPADDR", ipaddr); 00527 AST_LIST_INSERT_HEAD(&headp, newvariable, entries); 00528 pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest)); 00529 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries))) 00530 ast_var_delete(newvariable); 00531 } else 00532 dr[anscnt].dest[0] = '\0'; 00533 anscnt++; 00534 } else { 00535 /* No answers... Find the fewest number of digits from the 00536 number for which we have no answer. */ 00537 char tmp[AST_MAX_EXTENSION + 1] = ""; 00538 for (x = 0; x < (sizeof(tmp) - 1); x++) { 00539 tmp[x] = called_number[x]; 00540 if (!tmp[x]) 00541 break; 00542 if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) { 00543 /* Oops found something we can't match. If this is longer 00544 than the running hint, we have to consider it */ 00545 if (strlen(tmp) > strlen(hmd->exten)) { 00546 ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten)); 00547 } 00548 break; 00549 } 00550 } 00551 } 00552 } 00553 return anscnt; 00554 }
| static void* dundi_lookup_thread | ( | void * | data | ) | [static] |
Definition at line 558 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().
00559 { 00560 struct dundi_query_state *st = data; 00561 struct dundi_result dr[MAX_RESULTS]; 00562 struct dundi_ie_data ied; 00563 struct dundi_hint_metadata hmd; 00564 char eid_str[20]; 00565 int res, x; 00566 int ouranswers=0; 00567 int max = 999999; 00568 int expiration = dundi_cache_time; 00569 00570 ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 00571 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00572 memset(&ied, 0, sizeof(ied)); 00573 memset(&dr, 0, sizeof(dr)); 00574 memset(&hmd, 0, sizeof(hmd)); 00575 /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */ 00576 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 00577 for (x=0;x<st->nummaps;x++) 00578 ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd); 00579 if (ouranswers < 0) 00580 ouranswers = 0; 00581 for (x=0;x<ouranswers;x++) { 00582 if (dr[x].weight < max) 00583 max = dr[x].weight; 00584 } 00585 00586 if (max) { 00587 /* If we do not have a canonical result, keep looking */ 00588 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); 00589 if (res > 0) { 00590 /* Append answer in result */ 00591 ouranswers += res; 00592 } else { 00593 if ((res < -1) && (!ouranswers)) 00594 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending"); 00595 } 00596 } 00597 AST_LIST_LOCK(&peers); 00598 /* Truncate if "don't ask" isn't present */ 00599 if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK)) 00600 hmd.exten[0] = '\0'; 00601 if (ast_test_flag(st->trans, FLAG_DEAD)) { 00602 ast_debug(1, "Our transaction went away!\n"); 00603 st->trans->thread = 0; 00604 destroy_trans(st->trans, 0); 00605 } else { 00606 for (x=0;x<ouranswers;x++) { 00607 /* Add answers */ 00608 if (dr[x].expiration && (expiration > dr[x].expiration)) 00609 expiration = dr[x].expiration; 00610 dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); 00611 } 00612 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 00613 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); 00614 dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); 00615 st->trans->thread = 0; 00616 } 00617 AST_LIST_UNLOCK(&peers); 00618 ast_free(st); 00619 return NULL; 00620 }
| 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 4568 of file pbx_dundi.c.
References DUNDI_FLAG_MATCHMORE, and dundi_helper().
04569 { 04570 return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE); 04571 }
| int dundi_precache | ( | const char * | context, | |
| const char * | number | |||
| ) |
Pre-cache to push upstream peers.
Definition at line 3744 of file pbx_dundi.c.
References dundi_precache_internal().
Referenced by dundi_do_precache(), and process_precache().
03745 { 03746 dundi_eid *avoid[1] = { NULL, }; 03747 return dundi_precache_internal(context, number, dundi_ttl, avoid); 03748 }
| static void dundi_precache_full | ( | void | ) | [static] |
Definition at line 3647 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().
03648 { 03649 struct dundi_mapping *cur; 03650 struct ast_context *con; 03651 struct ast_exten *e; 03652 03653 AST_LIST_TRAVERSE(&mappings, cur, list) { 03654 ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext); 03655 ast_rdlock_contexts(); 03656 con = NULL; 03657 while ((con = ast_walk_contexts(con))) { 03658 if (strcasecmp(cur->lcontext, ast_get_context_name(con))) 03659 continue; 03660 /* Found the match, now queue them all up */ 03661 ast_rdlock_context(con); 03662 e = NULL; 03663 while ((e = ast_walk_context_extensions(con, e))) 03664 reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0); 03665 ast_unlock_context(con); 03666 } 03667 ast_unlock_contexts(); 03668 } 03669 }
| static int dundi_precache_internal | ( | const char * | context, | |
| const char * | number, | |||
| int | ttl, | |||
| dundi_eid * | avoids[] | |||
| ) | [static] |
Definition at line 3671 of file pbx_dundi.c.
References 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().
03672 { 03673 struct dundi_request dr; 03674 struct dundi_hint_metadata hmd; 03675 struct dundi_result dr2[MAX_RESULTS]; 03676 struct timeval start; 03677 struct dundi_mapping *maps = NULL, *cur; 03678 int nummaps = 0; 03679 int foundanswers; 03680 int foundcache, skipped, ttlms, ms; 03681 if (!context) 03682 context = "e164"; 03683 ast_debug(1, "Precache internal (%s@%s)!\n", number, context); 03684 03685 AST_LIST_LOCK(&peers); 03686 AST_LIST_TRAVERSE(&mappings, cur, list) { 03687 if (!strcasecmp(cur->dcontext, context)) 03688 nummaps++; 03689 } 03690 if (nummaps) { 03691 maps = alloca(nummaps * sizeof(*maps)); 03692 nummaps = 0; 03693 if (maps) { 03694 AST_LIST_TRAVERSE(&mappings, cur, list) { 03695 if (!strcasecmp(cur->dcontext, context)) 03696 maps[nummaps++] = *cur; 03697 } 03698 } 03699 } 03700 AST_LIST_UNLOCK(&peers); 03701 if (!nummaps || !maps) 03702 return -1; 03703 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03704 memset(&dr2, 0, sizeof(dr2)); 03705 memset(&dr, 0, sizeof(dr)); 03706 memset(&hmd, 0, sizeof(hmd)); 03707 dr.dr = dr2; 03708 ast_copy_string(dr.number, number, sizeof(dr.number)); 03709 ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext)); 03710 dr.maxcount = MAX_RESULTS; 03711 dr.expiration = dundi_cache_time; 03712 dr.hmd = &hmd; 03713 dr.pfds[0] = dr.pfds[1] = -1; 03714 if (pipe(dr.pfds) < 0) { 03715 ast_log(LOG_WARNING, "pipe() failed: %s\n", strerror(errno)); 03716 return -1; 03717 } 03718 build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL); 03719 optimize_transactions(&dr, 0); 03720 foundanswers = 0; 03721 precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers); 03722 if (foundanswers) { 03723 if (dr.expiration > 0) 03724 reschedule_precache(dr.number, dr.dcontext, dr.expiration); 03725 else 03726 ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext); 03727 } 03728 start = ast_tvnow(); 03729 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) { 03730 if (dr.pfds[0] > -1) { 03731 ms = 100; 03732 ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); 03733 } else 03734 usleep(1); 03735 } 03736 cancel_request(&dr); 03737 if (dr.pfds[0] > -1) { 03738 close(dr.pfds[0]); 03739 close(dr.pfds[1]); 03740 } 03741 return 0; 03742 }
| static void* dundi_precache_thread | ( | void * | data | ) | [static] |
Definition at line 622 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().
00623 { 00624 struct dundi_query_state *st = data; 00625 struct dundi_ie_data ied; 00626 struct dundi_hint_metadata hmd; 00627 char eid_str[20]; 00628 00629 ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, 00630 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00631 memset(&ied, 0, sizeof(ied)); 00632 00633 /* Now produce precache */ 00634 dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids); 00635 00636 AST_LIST_LOCK(&peers); 00637 /* Truncate if "don't ask" isn't present */ 00638 if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK)) 00639 hmd.exten[0] = '\0'; 00640 if (ast_test_flag(st->trans, FLAG_DEAD)) { 00641 ast_debug(1, "Our transaction went away!\n"); 00642 st->trans->thread = 0; 00643 destroy_trans(st->trans, 0); 00644 } else { 00645 dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 00646 st->trans->thread = 0; 00647 } 00648 AST_LIST_UNLOCK(&peers); 00649 ast_free(st); 00650 return NULL; 00651 }
| static int dundi_prop_precache | ( | struct dundi_transaction * | trans, | |
| struct dundi_ies * | ies, | |||
| char * | ccontext | |||
| ) | [static] |
Definition at line 841 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, s, 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().
00842 { 00843 struct dundi_query_state *st; 00844 int totallen; 00845 int x,z; 00846 struct dundi_ie_data ied; 00847 char *s; 00848 struct dundi_result dr2[MAX_RESULTS]; 00849 struct dundi_request dr; 00850 struct dundi_hint_metadata hmd; 00851 00852 struct dundi_mapping *cur; 00853 int mapcount; 00854 int skipfirst = 0; 00855 00856 pthread_t lookupthread; 00857 00858 memset(&dr2, 0, sizeof(dr2)); 00859 memset(&dr, 0, sizeof(dr)); 00860 memset(&hmd, 0, sizeof(hmd)); 00861 00862 /* Forge request structure to hold answers for cache */ 00863 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; 00864 dr.dr = dr2; 00865 dr.maxcount = MAX_RESULTS; 00866 dr.expiration = dundi_cache_time; 00867 dr.hmd = &hmd; 00868 dr.pfds[0] = dr.pfds[1] = -1; 00869 trans->parent = &dr; 00870 ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext)); 00871 ast_copy_string(dr.number, ies->called_number, sizeof(dr.number)); 00872 00873 for (x=0;x<ies->anscount;x++) { 00874 if (trans->parent->respcount < trans->parent->maxcount) { 00875 /* Make sure it's not already there */ 00876 for (z=0;z<trans->parent->respcount;z++) { 00877 if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) && 00878 !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data)) 00879 break; 00880 } 00881 if (z == trans->parent->respcount) { 00882 /* Copy into parent responses */ 00883 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags); 00884 trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol; 00885 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight); 00886 trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid; 00887 if (ies->expiration > 0) 00888 trans->parent->dr[trans->parent->respcount].expiration = ies->expiration; 00889 else 00890 trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; 00891 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 00892 sizeof(trans->parent->dr[trans->parent->respcount].eid_str), 00893 &ies->answers[x]->eid); 00894 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data, 00895 sizeof(trans->parent->dr[trans->parent->respcount].dest)); 00896 ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol), 00897 sizeof(trans->parent->dr[trans->parent->respcount].tech)); 00898 trans->parent->respcount++; 00899 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 00900 } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) { 00901 /* Update weight if appropriate */ 00902 trans->parent->dr[z].weight = ies->answers[x]->weight; 00903 } 00904 } else 00905 ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n", 00906 trans->parent->number, trans->parent->dcontext); 00907 00908 } 00909 /* Save all the results (if any) we had. Even if no results, still cache lookup. */ 00910 cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1); 00911 if (ies->hint) 00912 cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration); 00913 00914 totallen = sizeof(struct dundi_query_state); 00915 /* Count matching map entries */ 00916 mapcount = 0; 00917 AST_LIST_TRAVERSE(&mappings, cur, list) { 00918 if (!strcasecmp(cur->dcontext, ccontext)) 00919 mapcount++; 00920 } 00921 00922 /* If no maps, return -1 immediately */ 00923 if (!mapcount) 00924 return -1; 00925 00926 if (ies->eidcount > 1) { 00927 /* Since it is a requirement that the first EID is the authenticating host 00928 and the last EID is the root, it is permissible that the first and last EID 00929 could be the same. In that case, we should go ahead copy only the "root" section 00930 since we will not need it for authentication. */ 00931 if (!ast_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) 00932 skipfirst = 1; 00933 } 00934 00935 /* Prepare to run a query and then propagate that as necessary */ 00936 totallen += mapcount * sizeof(struct dundi_mapping); 00937 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); 00938 st = ast_calloc(1, totallen); 00939 if (st) { 00940 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); 00941 ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); 00942 st->trans = trans; 00943 st->ttl = ies->ttl - 1; 00944 st->nocache = ies->cbypass; 00945 if (st->ttl < 0) 00946 st->ttl = 0; 00947 s = st->fluffy; 00948 for (x=skipfirst;ies->eids[x];x++) { 00949 st->eids[x-skipfirst] = (dundi_eid *)s; 00950 *st->eids[x-skipfirst] = *ies->eids[x]; 00951 st->directs[x-skipfirst] = ies->eid_direct[x]; 00952 s += sizeof(dundi_eid); 00953 } 00954 /* Append mappings */ 00955 x = 0; 00956 st->maps = (struct dundi_mapping *)s; 00957 AST_LIST_TRAVERSE(&mappings, cur, list) { 00958 if (!strcasecmp(cur->dcontext, ccontext)) { 00959 if (x < mapcount) { 00960 st->maps[x] = *cur; 00961 st->maps[x].list.next = NULL; 00962 x++; 00963 } 00964 } 00965 } 00966 st->nummaps = mapcount; 00967 ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context); 00968 trans->thread = 1; 00969 if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) { 00970 trans->thread = 0; 00971 ast_log(LOG_WARNING, "Unable to create thread!\n"); 00972 ast_free(st); 00973 memset(&ied, 0, sizeof(ied)); 00974 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); 00975 dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 00976 return -1; 00977 } 00978 } else { 00979 ast_log(LOG_WARNING, "Out of memory!\n"); 00980 memset(&ied, 0, sizeof(ied)); 00981 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); 00982 dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); 00983 return -1; 00984 } 00985 return 0; 00986 }
| static int dundi_query | ( | struct dundi_transaction * | trans | ) | [static] |
Definition at line 3180 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().
03181 { 03182 struct dundi_ie_data ied; 03183 int x; 03184 if (!trans->parent) { 03185 ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n"); 03186 return -1; 03187 } 03188 memset(&ied, 0, sizeof(ied)); 03189 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03190 if (!dundi_eid_zero(&trans->us_eid)) 03191 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 03192 for (x=0;x<trans->eidcount;x++) 03193 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); 03194 dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid); 03195 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03196 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03197 if (trans->autokilltimeout) 03198 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03199 return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied); 03200 }
| int dundi_query_eid | ( | struct dundi_entity_info * | dei, | |
| const char * | dcontext, | |||
| dundi_eid | eid | |||
| ) |
Retrieve information on a specific EID.
Definition at line 3797 of file pbx_dundi.c.
References dundi_query_eid_internal().
Referenced by dundi_do_query().
03798 { 03799 dundi_eid *avoid[1] = { NULL, }; 03800 struct dundi_hint_metadata hmd; 03801 memset(&hmd, 0, sizeof(hmd)); 03802 return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid); 03803 }
| 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 3750 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().
03751 { 03752 int res; 03753 struct dundi_request dr; 03754 dundi_eid *rooteid=NULL; 03755 int x; 03756 int ttlms; 03757 int skipped=0; 03758 int foundcache=0; 03759 struct timeval start; 03760 03761 ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; 03762 03763 for (x=0;avoid[x];x++) 03764 rooteid = avoid[x]; 03765 /* Now perform real check */ 03766 memset(&dr, 0, sizeof(dr)); 03767 dr.hmd = hmd; 03768 dr.dei = dei; 03769 dr.pfds[0] = dr.pfds[1] = -1; 03770 ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); 03771 memcpy(&dr.query_eid, eid, sizeof(dr.query_eid)); 03772 if (rooteid) 03773 dr.root_eid = *rooteid; 03774 /* Create transactions */ 03775 build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL); 03776 03777 /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't 03778 do this earlier because we didn't know if we were going to have transactions 03779 or not. */ 03780 if (!ttl) { 03781 ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); 03782 return 0; 03783 } 03784 03785 /* Optimize transactions */ 03786 optimize_transactions(&dr, 9999); 03787 /* Actually perform transactions */ 03788 query_transactions(&dr); 03789 /* Wait for transaction to come back */ 03790 start = ast_tvnow(); 03791 while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) 03792 usleep(1); 03793 res = dr.respcount; 03794 return res; 03795 }
| static int dundi_query_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 3904 of file pbx_dundi.c.
References 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_module_user_add, ast_module_user_remove, 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().
03905 { 03906 struct ast_module_user *u; 03907 AST_DECLARE_APP_ARGS(args, 03908 AST_APP_ARG(number); 03909 AST_APP_ARG(context); 03910 AST_APP_ARG(options); 03911 ); 03912 struct ast_flags opts = { 0, }; 03913 char *parse; 03914 struct dundi_result_datastore *drds; 03915 struct ast_datastore *datastore; 03916 03917 u = ast_module_user_add(chan); 03918 03919 if (ast_strlen_zero(data)) { 03920 ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n"); 03921 ast_module_user_remove(u); 03922 return -1; 03923 } 03924 03925 if (!chan) { 03926 ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n"); 03927 ast_module_user_remove(u); 03928 return -1; 03929 } 03930 03931 parse = ast_strdupa(data); 03932 03933 AST_STANDARD_APP_ARGS(args, parse); 03934 03935 if (!ast_strlen_zero(args.options)) 03936 ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options); 03937 03938 if (ast_strlen_zero(args.context)) 03939 args.context = "e164"; 03940 03941 if (!(drds = ast_calloc(1, sizeof(*drds)))) { 03942 ast_module_user_remove(u); 03943 return -1; 03944 } 03945 03946 drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1); 03947 snprintf(buf, len, "%u", drds->id); 03948 03949 if (!(datastore = ast_datastore_alloc(&dundi_result_datastore_info, buf))) { 03950 drds_destroy(drds); 03951 ast_module_user_remove(u); 03952 return -1; 03953 } 03954 03955 datastore->data = drds; 03956 03957 drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, 03958 args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE)); 03959 03960 if (drds->num_results > 0) 03961 sort_results(drds->results, drds->num_results); 03962 03963 ast_channel_lock(chan); 03964 ast_channel_datastore_add(chan, datastore); 03965 ast_channel_unlock(chan); 03966 03967 ast_module_user_remove(u); 03968 03969 return 0; 03970 }
| static void* dundi_query_thread | ( | void * | data | ) | [static] |
Definition at line 655 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().
00656 { 00657 struct dundi_query_state *st = data; 00658 struct dundi_entity_info dei; 00659 struct dundi_ie_data ied; 00660 struct dundi_hint_metadata hmd; 00661 char eid_str[20]; 00662 int res; 00663 00664 ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, 00665 st->eids[0] ? ast_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); 00666 memset(&ied, 0, sizeof(ied)); 00667 memset(&dei, 0, sizeof(dei)); 00668 memset(&hmd, 0, sizeof(hmd)); 00669 if (!ast_eid_cmp(&st->trans->us_eid, &st->reqeid)) { 00670 /* Ooh, it's us! */ 00671 ast_debug(1, "Neat, someone look for us!\n"); 00672 ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit)); 00673 ast_copy_string(dei.org, org, sizeof(dei.org)); 00674 ast_copy_string(dei.locality, locality, sizeof(dei.locality)); 00675 ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov)); 00676 ast_copy_string(dei.country, country, sizeof(dei.country)); 00677 ast_copy_string(dei.email, email, sizeof(dei.email)); 00678 ast_copy_string(dei.phone, phone, sizeof(dei.phone)); 00679 res = 1; 00680 } else { 00681 /* If we do not have a canonical result, keep looking */ 00682 res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids); 00683 } 00684 AST_LIST_LOCK(&peers); 00685 if (ast_test_flag(st->trans, FLAG_DEAD)) { 00686 ast_debug(1, "Our transaction went away!\n"); 00687 st->trans->thread = 0; 00688 destroy_trans(st->trans, 0); 00689 } else { 00690 if (res) { 00691 dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit); 00692 dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org); 00693 dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality); 00694 dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov); 00695 dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country); 00696 dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email); 00697 dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone); 00698 if (!ast_strlen_zero(dei.ipaddr)) 00699 dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr); 00700 } 00701 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 00702 dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); 00703 st->trans->thread = 0; 00704 } 00705 AST_LIST_UNLOCK(&peers); 00706 ast_free(st); 00707 return NULL; 00708 }
| static void dundi_reject | ( | struct dundi_hdr * | h, | |
| struct sockaddr_in * | sin | |||
| ) | [static] |
Definition at line 367 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().
00368 { 00369 struct { 00370 struct dundi_packet pack; 00371 struct dundi_hdr hdr; 00372 } tmp; 00373 struct dundi_transaction trans; 00374 /* Never respond to an INVALID with another INVALID */ 00375 if (h->cmdresp == DUNDI_COMMAND_INVALID) 00376 return; 00377 memset(&tmp, 0, sizeof(tmp)); 00378 memset(&trans, 0, sizeof(trans)); 00379 memcpy(&trans.addr, sin, sizeof(trans.addr)); 00380 tmp.hdr.strans = h->dtrans; 00381 tmp.hdr.dtrans = h->strans; 00382 tmp.hdr.iseqno = h->oseqno; 00383 tmp.hdr.oseqno = h->iseqno; 00384 tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID; 00385 tmp.hdr.cmdflags = 0; 00386 tmp.pack.h = (struct dundi_hdr *)tmp.pack.data; 00387 tmp.pack.datalen = sizeof(struct dundi_hdr); 00388 tmp.pack.parent = &trans; 00389 dundi_xmit(&tmp.pack); 00390 }
| static int dundi_result_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 3984 of file pbx_dundi.c.
References AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_datastore::data, dundi_result::dest, LOG_ERROR, LOG_WARNING, num, dundi_result_datastore::num_results, parse(), dundi_result_datastore::results, and dundi_result::tech.
03985 { 03986 struct ast_module_user *u; 03987 AST_DECLARE_APP_ARGS(args, 03988 AST_APP_ARG(id); 03989 AST_APP_ARG(resultnum); 03990 ); 03991 char *parse; 03992 unsigned int num; 03993 struct dundi_result_datastore *drds; 03994 struct ast_datastore *datastore; 03995 int res = -1; 03996 03997 u = ast_module_user_add(chan); 03998 03999 if (ast_strlen_zero(data)) { 04000 ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n"); 04001 goto finish; 04002 } 04003 04004 if (!chan) { 04005 ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n"); 04006 goto finish; 04007 } 04008 04009 parse = ast_strdupa(data); 04010 04011 AST_STANDARD_APP_ARGS(args, parse); 04012 04013 if (ast_strlen_zero(args.id)) { 04014 ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n"); 04015 goto finish; 04016 } 04017 04018 if (ast_strlen_zero(args.resultnum)) { 04019 ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n"); 04020 goto finish; 04021 } 04022 04023 ast_channel_lock(chan); 04024 datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id); 04025 ast_channel_unlock(chan); 04026 04027 if (!datastore) { 04028 ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id); 04029 goto finish; 04030 } 04031 04032 drds = datastore->data; 04033 04034 if (!strcasecmp(args.resultnum, "getnum")) { 04035 snprintf(buf, len, "%u", drds->num_results); 04036 res = 0; 04037 goto finish; 04038 } 04039 04040 if (sscanf(args.resultnum, "%30u", &num) != 1) { 04041 ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n", 04042 args.resultnum); 04043 goto finish; 04044 } 04045 04046 if (num && num <= drds->num_results) { 04047 snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest); 04048 res = 0; 04049 } else 04050 ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id); 04051 04052 finish: 04053 ast_module_user_remove(u); 04054 04055 return res; 04056 }
| static int dundi_rexmit | ( | const void * | data | ) | [static] |
Definition at line 2963 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().
02964 { 02965 struct dundi_packet *pack = (struct dundi_packet *)data; 02966 int res; 02967 AST_LIST_LOCK(&peers); 02968 if (pack->retrans < 1) { 02969 pack->retransid = -1; 02970 if (!ast_test_flag(pack->parent, FLAG_ISQUAL)) 02971 ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", 02972 ast_inet_ntoa(pack->parent->addr.sin_addr), 02973 ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans)); 02974 destroy_trans(pack->parent, 1); 02975 res = 0; 02976 } else { 02977 /* Decrement retransmission, try again */ 02978 pack->retrans--; 02979 dundi_xmit(pack); 02980 res = 1; 02981 } 02982 AST_LIST_UNLOCK(&peers); 02983 return res; 02984 }
| static int dundi_send | ( | struct dundi_transaction * | trans, | |
| int | cmdresp, | |||
| int | flags, | |||
| int | final, | |||
| struct dundi_ie_data * | ied | |||
| ) | [static] |
Definition at line 2986 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().
02987 { 02988 struct dundi_packet *pack; 02989 int res; 02990 int len; 02991 char eid_str[20]; 02992 len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0); 02993 /* Reserve enough space for encryption */ 02994 if (ast_test_flag(trans, FLAG_ENCRYPT)) 02995 len += 384; 02996 pack = ast_calloc(1, len); 02997 if (pack) { 02998 pack->h = (struct dundi_hdr *)(pack->data); 02999 if (cmdresp != DUNDI_COMMAND_ACK) { 03000 pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack); 03001 pack->retrans = DUNDI_DEFAULT_RETRANS - 1; 03002 AST_LIST_INSERT_HEAD(&trans->packets, pack, list); 03003 } 03004 pack->parent = trans; 03005 pack->h->strans = htons(trans->strans); 03006 pack->h->dtrans = htons(trans->dtrans); 03007 pack->h->iseqno = trans->iseqno; 03008 pack->h->oseqno = trans->oseqno; 03009 pack->h->cmdresp = cmdresp; 03010 pack->datalen = sizeof(struct dundi_hdr); 03011 if (ied) { 03012 memcpy(pack->h->ies, ied->buf, ied->pos); 03013 pack->datalen += ied->pos; 03014 } 03015 if (final) { 03016 pack->h->cmdresp |= DUNDI_COMMAND_FINAL; 03017 ast_set_flag(trans, FLAG_FINAL); 03018 } 03019 pack->h->cmdflags = flags; 03020 if (cmdresp != DUNDI_COMMAND_ACK) { 03021 trans->oseqno++; 03022 trans->oseqno = trans->oseqno % 256; 03023 } 03024 trans->aseqno = trans->iseqno; 03025 /* If we have their public key, encrypt */ 03026 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 03027 switch(cmdresp) { 03028 case DUNDI_COMMAND_REGREQ: 03029 case DUNDI_COMMAND_REGRESPONSE: 03030 case DUNDI_COMMAND_DPDISCOVER: 03031 case DUNDI_COMMAND_DPRESPONSE: 03032 case DUNDI_COMMAND_EIDQUERY: 03033 case DUNDI_COMMAND_EIDRESPONSE: 03034 case DUNDI_COMMAND_PRECACHERQ: 03035 case DUNDI_COMMAND_PRECACHERP: 03036 if (dundidebug) 03037 dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr)); 03038 res = dundi_encrypt(trans, pack); 03039 break; 03040 default: 03041 res = 0; 03042 } 03043 } else 03044 res = 0; 03045 if (!res) 03046 res = dundi_xmit(pack); 03047 if (res) 03048 ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); 03049 03050 if (cmdresp == DUNDI_COMMAND_ACK) 03051 ast_free(pack); 03052 return res; 03053 } 03054 return -1; 03055 }
| static char* dundi_set_debug | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2195 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.
02196 { 02197 switch (cmd) { 02198 case CLI_INIT: 02199 e->command = "dundi set debug {on|off}"; 02200 e->usage = 02201 "Usage: dundi set debug {on|off}\n" 02202 " Enables/Disables dumping of DUNDi packets for debugging purposes\n"; 02203 return NULL; 02204 case CLI_GENERATE: 02205 return NULL; 02206 } 02207 02208 if (a->argc != e->args) 02209 return CLI_SHOWUSAGE; 02210 02211 if (!strncasecmp(a->argv[e->args -1], "on", 2)) { 02212 dundidebug = 1; 02213 ast_cli(a->fd, "DUNDi Debugging Enabled\n"); 02214 } else { 02215 dundidebug = 0; 02216 ast_cli(a->fd, "DUNDi Debugging Disabled\n"); 02217 } 02218 return CLI_SUCCESS; 02219 }
| static char* dundi_show_entityid | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2684 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.
02685 { 02686 char eid_str[20]; 02687 switch (cmd) { 02688 case CLI_INIT: 02689 e->command = "dundi show entityid"; 02690 e->usage = 02691 "Usage: dundi show entityid\n" 02692 " Displays the global entityid for this host.\n"; 02693 return NULL; 02694 case CLI_GENERATE: 02695 return NULL; 02696 } 02697 if (a->argc != 3) 02698 return CLI_SHOWUSAGE; 02699 AST_LIST_LOCK(&peers); 02700 ast_eid_to_str(eid_str, sizeof(eid_str), &global_eid); 02701 AST_LIST_UNLOCK(&peers); 02702 ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str); 02703 return CLI_SUCCESS; 02704 }
| static char* dundi_show_mappings | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2738 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.
02739 { 02740 #define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" 02741 #define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n" 02742 struct dundi_mapping *map; 02743 char fs[256]; 02744 char weight[8]; 02745 switch (cmd) { 02746 case CLI_INIT: 02747 e->command = "dundi show mappings"; 02748 e->usage = 02749 "Usage: dundi show mappings\n" 02750 " Lists all known DUNDi mappings.\n"; 02751 return NULL; 02752 case CLI_GENERATE: 02753 return NULL; 02754 } 02755 if (a->argc != 3) 02756 return CLI_SHOWUSAGE; 02757 AST_LIST_LOCK(&peers); 02758 ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination"); 02759 AST_LIST_TRAVERSE(&mappings, map, list) { 02760 snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map)); 02761 ast_cli(a->fd, FORMAT, map->dcontext, weight, 02762 ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, 02763 dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest); 02764 } 02765 AST_LIST_UNLOCK(&peers); 02766 return CLI_SUCCESS; 02767 #undef FORMAT 02768 #undef FORMAT2 02769 }
| static char* dundi_show_peer | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2487 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.
02488 { 02489 struct dundi_peer *peer; 02490 struct permission *p; 02491 char *order; 02492 char eid_str[20]; 02493 int x, cnt; 02494 switch (cmd) { 02495 case CLI_INIT: 02496 e->command = "dundi show peer"; 02497 e->usage = 02498 "Usage: dundi show peer [peer]\n" 02499 " Provide a detailed description of a specifid DUNDi peer.\n"; 02500 return NULL; 02501 case CLI_GENERATE: 02502 return complete_peer_helper(a->line, a->word, a->pos, a->n, 3); 02503 } 02504 if (a->argc != 4) 02505 return CLI_SHOWUSAGE; 02506 AST_LIST_LOCK(&peers); 02507 AST_LIST_TRAVERSE(&peers, peer, list) { 02508 if (!strcasecmp(ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3])) 02509 break; 02510 } 02511 if (peer) { 02512 switch(peer->order) { 02513 case 0: 02514 order = "Primary"; 02515 break; 02516 case 1: 02517 order = "Secondary"; 02518 break; 02519 case 2: 02520 order = "Tertiary"; 02521 break; 02522 case 3: 02523 order = "Quartiary"; 02524 break; 02525 default: 02526 order = "Unknown"; 02527 } 02528 ast_cli(a->fd, "Peer: %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); 02529 ast_cli(a->fd, "Model: %s\n", model2str(peer->model)); 02530 ast_cli(a->fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>"); 02531 ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no"); 02532 ast_cli(a->fd, "Reg: %s\n", peer->registerid < 0 ? "No" : "Yes"); 02533 ast_cli(a->fd, "In Key: %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey); 02534 ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey); 02535 if (!AST_LIST_EMPTY(&peer->include)) 02536 ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)"); 02537 AST_LIST_TRAVERSE(&peer->include, p, list) 02538 ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name); 02539 if (!AST_LIST_EMPTY(&peer->permit)) 02540 ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)"); 02541 AST_LIST_TRAVERSE(&peer->permit, p, list) 02542 ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name); 02543 cnt = 0; 02544 for (x = 0;x < DUNDI_TIMING_HISTORY; x++) { 02545 if (peer->lookups[x]) { 02546 if (!cnt) 02547 ast_cli(a->fd, "Last few query times:\n"); 02548 ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]); 02549 cnt++; 02550 } 02551 } 02552 if (cnt) 02553 ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms); 02554 } else 02555 ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]); 02556 AST_LIST_UNLOCK(&peers); 02557 return CLI_SUCCESS; 02558 }
| static char* dundi_show_peers | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2560 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.
02561 { 02562 #define FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n" 02563 #define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n" 02564 struct dundi_peer *peer; 02565 int registeredonly=0; 02566 char avgms[20]; 02567 char eid_str[20]; 02568 int online_peers = 0; 02569 int offline_peers = 0; 02570 int unmonitored_peers = 0; 02571 int total_peers = 0; 02572 switch (cmd) { 02573 case CLI_INIT: 02574 e->command = "dundi show peers [registered|include|exclude|begin]"; 02575 e->usage = 02576 "Usage: dundi show peers [registered|include|exclude|begin]\n" 02577 " Lists all known DUNDi peers.\n" 02578 " If 'registered' is present, only registered peers are shown.\n"; 02579 return NULL; 02580 case CLI_GENERATE: 02581 return NULL; 02582 } 02583 02584 if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5)) 02585 return CLI_SHOWUSAGE; 02586 if ((a->argc == 4)) { 02587 if (!strcasecmp(a->argv[3], "registered")) { 02588 registeredonly = 1; 02589 } else 02590 return CLI_SHOWUSAGE; 02591 } 02592 AST_LIST_LOCK(&peers); 02593 ast_cli(a->fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status"); 02594 AST_LIST_TRAVERSE(&peers, peer, list) { 02595 char status[20]; 02596 int print_line = -1; 02597 char srch[2000]; 02598 total_peers++; 02599 if (registeredonly && !peer->addr.sin_addr.s_addr) 02600 continue; 02601 if (peer->maxms) { 02602 if (peer->lastms < 0) { 02603 strcpy(status, "UNREACHABLE"); 02604 offline_peers++; 02605 } 02606 else if (peer->lastms > peer->maxms) { 02607 snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms); 02608 offline_peers++; 02609 } 02610 else if (peer->lastms) { 02611 snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms); 02612 online_peers++; 02613 } 02614 else { 02615 strcpy(status, "UNKNOWN"); 02616 offline_peers++; 02617 } 02618 } else { 02619 strcpy(status, "Unmonitored"); 02620 unmonitored_peers++; 02621 } 02622 if (peer->avgms) 02623 snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms); 02624 else 02625 strcpy(avgms, "Unavail"); 02626 snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 02627 peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", 02628 peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); 02629 02630 if (a->argc == 5) { 02631 if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) { 02632 print_line = -1; 02633 } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) { 02634 print_line = 1; 02635 } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) { 02636 print_line = -1; 02637 } else { 02638 print_line = 0; 02639 } 02640 } 02641 02642 if (print_line) { 02643 ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 02644 peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", 02645 peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); 02646 } 02647 } 02648 ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers); 02649 AST_LIST_UNLOCK(&peers); 02650 return CLI_SUCCESS; 02651 #undef FORMAT 02652 #undef FORMAT2 02653 }
| static char* dundi_show_precache | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2771 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, s, and ast_cli_entry::usage.
02772 { 02773 #define FORMAT2 "%-12.12s %-12.12s %-10.10s\n" 02774 #define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n" 02775 struct dundi_precache_queue *qe; 02776 int h,m,s; 02777 time_t now; 02778 switch (cmd) { 02779 case CLI_INIT: 02780 e->command = "dundi show precache"; 02781 e->usage = 02782 "Usage: dundi show precache\n" 02783 " Lists all known DUNDi scheduled precache updates.\n"; 02784 return NULL; 02785 case CLI_GENERATE: 02786 return NULL; 02787 } 02788 if (a->argc != 3) 02789 return CLI_SHOWUSAGE; 02790 time(&now); 02791 ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration"); 02792 AST_LIST_LOCK(&pcq); 02793 AST_LIST_TRAVERSE(&pcq, qe, list) { 02794 s = qe->expiration - now; 02795 h = s / 3600; 02796 s = s % 3600; 02797 m = s / 60; 02798 s = s % 60; 02799 ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s); 02800 } 02801 AST_LIST_UNLOCK(&pcq); 02802 02803 return CLI_SUCCESS; 02804 #undef FORMAT 02805 #undef FORMAT2 02806 }
| static char* dundi_show_requests | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2706 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.
02707 { 02708 #define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" 02709 #define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n" 02710 struct dundi_request *req; 02711 char eidstr[20]; 02712 switch (cmd) { 02713 case CLI_INIT: 02714 e->command = "dundi show requests"; 02715 e->usage = 02716 "Usage: dundi show requests\n" 02717 " Lists all known pending DUNDi requests.\n"; 02718 return NULL; 02719 case CLI_GENERATE: 02720 return NULL; 02721 } 02722 if (a->argc != 3) 02723 return CLI_SHOWUSAGE; 02724 AST_LIST_LOCK(&peers); 02725 ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp"); 02726 AST_LIST_TRAVERSE(&requests, req, list) { 02727 ast_cli(a->fd, FORMAT, req->number, req->dcontext, 02728 dundi_eid_zero(&req->root_eid) ? "<unspecified>" : ast_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount); 02729 } 02730 AST_LIST_UNLOCK(&peers); 02731 return CLI_SUCCESS; 02732 #undef FORMAT 02733 #undef FORMAT2 02734 }
| static char* dundi_show_trans | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2655 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.
02656 { 02657 #define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" 02658 #define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" 02659 struct dundi_transaction *trans; 02660 switch (cmd) { 02661 case CLI_INIT: 02662 e->command = "dundi show trans"; 02663 e->usage = 02664 "Usage: dundi show trans\n" 02665 " Lists all known DUNDi transactions.\n"; 02666 return NULL; 02667 case CLI_GENERATE: 02668 return NULL; 02669 } 02670 if (a->argc != 3) 02671 return CLI_SHOWUSAGE; 02672 AST_LIST_LOCK(&peers); 02673 ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack"); 02674 AST_LIST_TRAVERSE(&alltrans, trans, all) { 02675 ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), 02676 ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); 02677 } 02678 AST_LIST_UNLOCK(&peers); 02679 return CLI_SUCCESS; 02680 #undef FORMAT 02681 #undef FORMAT2 02682 }
| static char* dundi_store_history | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 2221 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.
02222 { 02223 switch (cmd) { 02224 case CLI_INIT: 02225 e->command = "dundi store history {on|off}"; 02226 e->usage = 02227 "Usage: dundi store history {on|off}\n" 02228 " Enables/Disables storing of DUNDi requests and times for debugging\n" 02229 "purposes\n"; 02230 return NULL; 02231 case CLI_GENERATE: 02232 return NULL; 02233 } 02234 02235 if (a->argc != e->args) 02236 return CLI_SHOWUSAGE; 02237 02238 if (!strncasecmp(a->argv[e->args -1], "on", 2)) { 02239 global_storehistory = 1; 02240 ast_cli(a->fd, "DUNDi History Storage Enabled\n"); 02241 } else { 02242 global_storehistory = 0; 02243 ast_cli(a->fd, "DUNDi History Storage Disabled\n"); 02244 } 02245 return CLI_SUCCESS; 02246 }
| static int dundi_xmit | ( | struct dundi_packet * | pack | ) | [static] |
Definition at line 2855 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().
02856 { 02857 int res; 02858 if (dundidebug) 02859 dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr)); 02860 res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr)); 02861 if (res < 0) { 02862 ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", 02863 ast_inet_ntoa(pack->parent->addr.sin_addr), 02864 ntohs(pack->parent->addr.sin_port), strerror(errno)); 02865 } 02866 if (res > 0) 02867 res = 0; 02868 return res; 02869 }
| static int dundifunc_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | num, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 3813 of file pbx_dundi.c.
References AST_APP_ARG, ast_app_parse_options(), AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, 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().
03814 { 03815 int results; 03816 int x; 03817 struct ast_module_user *u; 03818 struct dundi_result dr[MAX_RESULTS]; 03819 AST_DECLARE_APP_ARGS(args, 03820 AST_APP_ARG(number); 03821 AST_APP_ARG(context); 03822 AST_APP_ARG(options); 03823 ); 03824 char *parse; 03825 struct ast_flags opts = { 0, }; 03826 03827 buf[0] = '\0'; 03828 03829 if (ast_strlen_zero(num)) { 03830 ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n"); 03831 return -1; 03832 } 03833 03834 u = ast_module_user_add(chan); 03835 03836 parse = ast_strdupa(num); 03837 03838 AST_STANDARD_APP_ARGS(args, parse); 03839 03840 if (!ast_strlen_zero(args.options)) { 03841 ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options); 03842 } 03843 if (ast_strlen_zero(args.context)) { 03844 args.context = "e164"; 03845 } 03846 03847 results = dundi_lookup(dr, MAX_RESULTS, NULL, args.context, args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE)); 03848 if (results > 0) { 03849 sort_results(dr, results); 03850 for (x = 0; x < results; x++) { 03851 if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) { 03852 snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest); 03853 break; 03854 } 03855 } 03856 } 03857 03858 ast_module_user_remove(u); 03859 03860 return 0; 03861 }
| static int encrypt_memcpy | ( | unsigned char * | dst, | |
| unsigned char * | src, | |||
| int | len, | |||
| unsigned char * | iv, | |||
| ast_aes_encrypt_key * | ecx | |||
| ) | [static] |
Definition at line 1270 of file pbx_dundi.c.
References ast_aes_encrypt.
Referenced by dundi_encrypt().
01271 { 01272 unsigned char curblock[16]; 01273 int x; 01274 memcpy(curblock, iv, sizeof(curblock)); 01275 while(len > 0) { 01276 for (x=0;x<16;x++) 01277 curblock[x] ^= src[x]; 01278 ast_aes_encrypt(curblock, dst, ecx); 01279 memcpy(curblock, dst, sizeof(curblock)); 01280 dst += 16; 01281 src += 16; 01282 len -= 16; 01283 } 01284 return 0; 01285 }
| static struct dundi_peer* find_peer | ( | dundi_eid * | eid | ) | [static, read] |
Definition at line 427 of file pbx_dundi.c.
References any_peer, ast_eid_cmp(), AST_LIST_TRAVERSE, and dundi_peer::eid.
00428 { 00429 struct dundi_peer *cur = NULL; 00430 00431 if (!eid) 00432 eid = &empty_eid; 00433 00434 AST_LIST_TRAVERSE(&peers, cur, list) { 00435 if (!ast_eid_cmp(&cur->eid,eid)) 00436 break; 00437 } 00438 00439 if (!cur && any_peer) 00440 cur = any_peer; 00441 00442 return cur; 00443 }
| static struct dundi_transaction* find_transaction | ( | struct dundi_hdr * | hdr, | |
| struct sockaddr_in * | sin | |||
| ) | [static, read] |
Definition at line 325 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 acf_transaction_read(), acf_transaction_write(), ast_odbc_release_obj(), commit_exec(), handle_frame(), and rollback_exec().
00326 { 00327 struct dundi_transaction *trans; 00328 00329 /* Look for an exact match first */ 00330 AST_LIST_TRAVERSE(&alltrans, trans, all) { 00331 if (!inaddrcmp(&trans->addr, sin) && 00332 ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || 00333 ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { 00334 if (hdr->strans) 00335 trans->dtrans = ntohs(hdr->strans) & 32767; 00336 return trans; 00337 } 00338 } 00339 00340 switch(hdr->cmdresp & 0x7f) { 00341 case DUNDI_COMMAND_DPDISCOVER: 00342 case DUNDI_COMMAND_EIDQUERY: 00343 case DUNDI_COMMAND_PRECACHERQ: 00344 case DUNDI_COMMAND_REGREQ: 00345 case DUNDI_COMMAND_NULL: 00346 case DUNDI_COMMAND_ENCRYPT: 00347 if (!hdr->strans) 00348 break; 00349 /* Create new transaction */ 00350 if (!(trans = create_transaction(NULL))) 00351 break; 00352 memcpy(&trans->addr, sin, sizeof(trans->addr)); 00353 trans->dtrans = ntohs(hdr->strans) & 32767; 00354 default: 00355 break; 00356 } 00357 00358 return trans; 00359 }
| static int get_mapping_weight | ( | struct dundi_mapping * | map | ) | [static] |
Definition at line 471 of file pbx_dundi.c.
References dundi_mapping::_weight, buf, MAX_WEIGHT, pbx_substitute_variables_helper(), and dundi_mapping::weightstr.
Referenced by dundi_lookup_local(), and dundi_show_mappings().
00472 { 00473 char buf[32]; 00474 00475 buf[0] = 0; 00476 if (map->weightstr) { 00477 pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1); 00478 if (sscanf(buf, "%30d", &map->_weight) != 1) 00479 map->_weight = MAX_WEIGHT; 00480 } 00481 00482 return map->_weight; 00483 }
| static int get_trans_id | ( | void | ) | [static] |
Definition at line 392 of file pbx_dundi.c.
References AST_LIST_TRAVERSE, ast_random(), and dundi_transaction::strans.
Referenced by create_transaction(), and reset_transaction().
00393 { 00394 struct dundi_transaction *t; 00395 int stid = (ast_random() % 32766) + 1; 00396 int tid = stid; 00397 00398 do { 00399 AST_LIST_TRAVERSE(&alltrans, t, all) { 00400 if (t->strans == tid) 00401 break; 00402 } 00403 if (!t) 00404 return tid; 00405 tid = (tid % 32766) + 1; 00406 } while (tid != stid); 00407 00408 return 0; 00409 }
| static int handle_command_response | ( | struct dundi_transaction * | trans, | |
| struct dundi_hdr * | hdr, | |||
| int | datalen, | |||
| int | encrypted | |||
| ) | [static] |
Definition at line 1477 of file pbx_dundi.c.
References dundi_peer::addr, dundi_transaction::addr, dundi_ies::anscount, dundi_ies::answers, any_peer, apply_peer(), dundi_transaction::aseqno, ast_calloc, ast_clear_flag, ast_clear_flag_nonstd, ast_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().
01478 { 01479 /* Handle canonical command / response */ 01480 int final = hdr->cmdresp & 0x80; 01481 int cmd = hdr->cmdresp & 0x7f; 01482 int x,y,z; 01483 int resp; 01484 int res; 01485 int authpass=0; 01486 unsigned char *bufcpy; 01487 #ifdef LOW_MEMORY 01488 struct dundi_ie_data *ied = ast_calloc(1, sizeof(*ied)); 01489 #else 01490 struct dundi_ie_data _ied = { 01491 .pos = 0, 01492 }; 01493 struct dundi_ie_data *ied = &_ied; 01494 #endif 01495 struct dundi_ies ies = { 01496 .eidcount = 0, 01497 }; 01498 struct dundi_peer *peer = NULL; 01499 char eid_str[20]; 01500 char eid_str2[20]; 01501 int retval = -1; 01502 01503 if (!ied) { 01504 return -1; 01505 } 01506 01507 if (datalen) { 01508 bufcpy = alloca(datalen); 01509 if (!bufcpy) { 01510 goto return_cleanup; 01511 } 01512 /* Make a copy for parsing */ 01513 memcpy(bufcpy, hdr->ies, datalen); 01514 ast_debug(1, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : ""); 01515 if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) { 01516 ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n"); 01517 goto return_cleanup; 01518 } 01519 } 01520 switch(cmd) { 01521 case DUNDI_COMMAND_DPDISCOVER: 01522 case DUNDI_COMMAND_EIDQUERY: 01523 case DUNDI_COMMAND_PRECACHERQ: 01524 if (cmd == DUNDI_COMMAND_EIDQUERY) 01525 resp = DUNDI_COMMAND_EIDRESPONSE; 01526 else if (cmd == DUNDI_COMMAND_PRECACHERQ) 01527 resp = DUNDI_COMMAND_PRECACHERP; 01528 else 01529 resp = DUNDI_COMMAND_DPRESPONSE; 01530 /* A dialplan or entity discover -- qualify by highest level entity */ 01531 peer = find_peer(ies.eids[0]); 01532 if (!peer) { 01533 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); 01534 dundi_send(trans, resp, 0, 1, ied); 01535 } else { 01536 int hasauth = 0; 01537 trans->us_eid = peer->us_eid; 01538 if (strlen(peer->inkey)) { 01539 hasauth = encrypted; 01540 } else 01541 hasauth = 1; 01542 if (hasauth) { 01543 /* Okay we're authentiated and all, now we check if they're authorized */ 01544 if (!ies.called_context) 01545 ies.called_context = "e164"; 01546 if (cmd == DUNDI_COMMAND_EIDQUERY) { 01547 res = dundi_answer_entity(trans, &ies, ies.called_context); 01548 } else { 01549 if (ast_strlen_zero(ies.called_number)) { 01550 /* They're not permitted to access that context */ 01551 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity"); 01552 dundi_send(trans, resp, 0, 1, ied); 01553 } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) && 01554 (peer->model & DUNDI_MODEL_INBOUND) && 01555 has_permission(&peer->permit, ies.called_context)) { 01556 res = dundi_answer_query(trans, &ies, ies.called_context); 01557 if (res < 0) { 01558 /* There is no such dundi context */ 01559 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); 01560 dundi_send(trans, resp, 0, 1, ied); 01561 } 01562 } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) && 01563 (peer->pcmodel & DUNDI_MODEL_INBOUND) && 01564 has_permission(&peer->include, ies.called_context)) { 01565 res = dundi_prop_precache(trans, &ies, ies.called_context); 01566 if (res < 0) { 01567 /* There is no such dundi context */ 01568 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); 01569 dundi_send(trans, resp, 0, 1, ied); 01570 } 01571 } else { 01572 /* They're not permitted to access that context */ 01573 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied"); 01574 dundi_send(trans, resp, 0, 1, ied); 01575 } 01576 } 01577 } else { 01578 /* They're not permitted to access that context */ 01579 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted"); 01580 dundi_send(trans, resp, 0, 1, ied); 01581 } 01582 } 01583 break; 01584 case DUNDI_COMMAND_REGREQ: 01585 /* A register request -- should only have one entity */ 01586 peer = find_peer(ies.eids[0]); 01587 01588 /* if the peer is not found and we have a valid 'any_peer' setting */ 01589 if (any_peer && peer == any_peer) { 01590 /* copy any_peer into a new peer object */ 01591 peer = ast_calloc(1, sizeof(*peer)); 01592 if (peer) { 01593 deep_copy_peer(peer, any_peer); 01594 01595 /* set EID to remote EID */ 01596 peer->eid = *ies.eids[0]; 01597 01598 AST_LIST_LOCK(&peers); 01599 AST_LIST_INSERT_HEAD(&peers, peer, list); 01600 AST_LIST_UNLOCK(&peers); 01601 } 01602 } 01603 01604 if (!peer || !peer->dynamic) { 01605 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); 01606 dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); 01607 } else { 01608 int hasauth = 0; 01609 trans->us_eid = peer->us_eid; 01610 if (!ast_strlen_zero(peer->inkey)) { 01611 hasauth = encrypted; 01612 } else 01613 hasauth = 1; 01614 if (hasauth) { 01615 int expire = default_expiration; 01616 char data[256]; 01617 int needqual = 0; 01618 AST_SCHED_DEL(sched, peer->registerexpire); 01619 peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); 01620 snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr), 01621 ntohs(trans->addr.sin_port), expire); 01622 ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data); 01623 if (inaddrcmp(&peer->addr, &trans->addr)) { 01624 ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n", 01625 ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), 01626 ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port)); 01627 needqual = 1; 01628 } 01629 01630 memcpy(&peer->addr, &trans->addr, sizeof(peer->addr)); 01631 dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration); 01632 dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); 01633 if (needqual) 01634 qualify_peer(peer, 1); 01635 } 01636 } 01637 break; 01638 case DUNDI_COMMAND_DPRESPONSE: 01639 /* A dialplan response, lets see what we got... */ 01640 if (ies.cause < 1) { 01641 /* Success of some sort */ 01642 ast_debug(1, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount); 01643 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01644 authpass = encrypted; 01645 } else 01646 authpass = 1; 01647 if (authpass) { 01648 /* Pass back up answers */ 01649 if (trans->parent && trans->parent->dr) { 01650 y = trans->parent->respcount; 01651 for (x=0;x<ies.anscount;x++) { 01652 if (trans->parent->respcount < trans->parent->maxcount) { 01653 /* Make sure it's not already there */ 01654 for (z=0;z<trans->parent->respcount;z++) { 01655 if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) && 01656 !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data)) 01657 break; 01658 } 01659 if (z == trans->parent->respcount) { 01660 /* Copy into parent responses */ 01661 trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags); 01662 trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol; 01663 trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight); 01664 trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid; 01665 if (ies.expiration > 0) 01666 trans->parent->dr[trans->parent->respcount].expiration = ies.expiration; 01667 else 01668 trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; 01669 ast_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, 01670 sizeof(trans->parent->dr[trans->parent->respcount].eid_str), 01671 &ies.answers[x]->eid); 01672 ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data, 01673 sizeof(trans->parent->dr[trans->parent->respcount].dest)); 01674 ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol), 01675 sizeof(trans->parent->dr[trans->parent->respcount].tech)); 01676 trans->parent->respcount++; 01677 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 01678 } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) { 01679 /* Update weight if appropriate */ 01680 trans->parent->dr[z].weight = ies.answers[x]->weight; 01681 } 01682 } else 01683 ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n", 01684 trans->parent->number, trans->parent->dcontext); 01685 } 01686 /* Save all the results (if any) we had. Even if no results, still cache lookup. Let 01687 the cache know if this request was unaffected by our entity list. */ 01688 cache_save(&trans->them_eid, trans->parent, y, 01689 ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0); 01690 if (ies.hint) { 01691 cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration); 01692 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) 01693 ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); 01694 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) { 01695 if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) { 01696 ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data, 01697 sizeof(trans->parent->hmd->exten)); 01698 } 01699 } else { 01700 ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); 01701 } 01702 } 01703 if (ies.expiration > 0) { 01704 if (trans->parent->expiration > ies.expiration) { 01705 trans->parent->expiration = ies.expiration; 01706 } 01707 } 01708 } 01709 /* Close connection if not final */ 01710 if (!final) 01711 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01712 } 01713 01714 } else { 01715 /* Auth failure, check for data */ 01716 if (!final) { 01717 /* Cancel if they didn't already */ 01718 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01719 } 01720 } 01721 break; 01722 case DUNDI_COMMAND_EIDRESPONSE: 01723 /* A dialplan response, lets see what we got... */ 01724 if (ies.cause < 1) { 01725 /* Success of some sort */ 01726 ast_debug(1, "Looks like success of some sort (%d)\n", ies.cause); 01727 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01728 authpass = encrypted; 01729 } else 01730 authpass = 1; 01731 if (authpass) { 01732 /* Pass back up answers */ 01733 if (trans->parent && trans->parent->dei && ies.q_org) { 01734 if (!trans->parent->respcount) { 01735 trans->parent->respcount++; 01736 if (ies.q_dept) 01737 ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit)); 01738 if (ies.q_org) 01739 ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org)); 01740 if (ies.q_locality) 01741 ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality)); 01742 if (ies.q_stateprov) 01743 ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov)); 01744 if (ies.q_country) 01745 ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country)); 01746 if (ies.q_email) 01747 ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email)); 01748 if (ies.q_phone) 01749 ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone)); 01750 if (ies.q_ipaddr) 01751 ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr)); 01752 if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) { 01753 /* If it's them, update our address */ 01754 ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr)); 01755 } 01756 } 01757 if (ies.hint) { 01758 if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) 01759 ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); 01760 } 01761 } 01762 /* Close connection if not final */ 01763 if (!final) 01764 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01765 } 01766 01767 } else { 01768 /* Auth failure, check for data */ 01769 if (!final) { 01770 /* Cancel if they didn't already */ 01771 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01772 } 01773 } 01774 break; 01775 case DUNDI_COMMAND_REGRESPONSE: 01776 /* A dialplan response, lets see what we got... */ 01777 if (ies.cause < 1) { 01778 int hasauth; 01779 /* Success of some sort */ 01780 if (ast_test_flag(trans, FLAG_ENCRYPT)) { 01781 hasauth = encrypted; 01782 } else 01783 hasauth = 1; 01784 01785 if (!hasauth) { 01786 ast_log(LOG_NOTICE, "Reponse to register not authorized!\n"); 01787 if (!final) { 01788 dundi_ie_append_cause(ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer"); 01789 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, ied); 01790 } 01791 } else { 01792 ast_debug(1, "Yay, we've registered as '%s' to '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid), 01793 ast_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid)); 01794 /* Close connection if not final */ 01795 if (!final) 01796 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01797 } 01798 } else { 01799 /* Auth failure, cancel if they didn't for some reason */ 01800 if (!final) { 01801 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01802 } 01803 } 01804 break; 01805 case DUNDI_COMMAND_INVALID: 01806 case DUNDI_COMMAND_NULL: 01807 case DUNDI_COMMAND_PRECACHERP: 01808 /* Do nothing special */ 01809 if (!final) 01810 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01811 break; 01812 case DUNDI_COMMAND_ENCREJ: 01813 if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || AST_LIST_EMPTY(&trans->lasttrans) || !(peer = find_peer(&trans->them_eid))) { 01814 /* No really, it's over at this point */ 01815 if (!final) 01816 dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); 01817 } else { 01818 /* Send with full key */ 01819 ast_set_flag(trans, FLAG_SENDFULLKEY); 01820 if (final) { 01821 /* Ooops, we got a final message, start by sending ACK... */ 01822 dundi_ack(trans, hdr->cmdresp & 0x80); 01823 trans->aseqno = trans->iseqno; 01824 /* Now, we gotta create a new transaction */ 01825 if (!reset_transaction(trans)) { 01826 /* Make sure handle_frame doesn't destroy us */ 01827 hdr->cmdresp &= 0x7f; 01828 /* Parse the message we transmitted */ 01829 memset(&ies, 0, sizeof(ies)); 01830 dundi_parse_ies(&ies, (AST_LIST_FIRST(&trans->lasttrans))->h->ies, (AST_LIST_FIRST(&trans->lasttrans))->datalen - sizeof(struct dundi_hdr)); 01831 /* Reconstruct outgoing encrypted packet */ 01832 memset(ied, 0, sizeof(*ied)); 01833 dundi_ie_append_eid(ied, DUNDI_IE_EID, &trans->us_eid); 01834 dundi_ie_append_raw(ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); 01835 dundi_ie_append_raw(ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); 01836 if (ies.encblock) 01837 dundi_ie_append_encdata(ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen); 01838 dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, (AST_LIST_FIRST(&trans->lasttrans))->h->cmdresp & 0x80, ied); 01839 peer->sentfullkey = 1; 01840 } 01841 } 01842 } 01843 break; 01844 case DUNDI_COMMAND_ENCRYPT: 01845 if (!encrypted) { 01846 /* No nested encryption! */ 01847 if ((trans->iseqno == 1) && !trans->oseqno) { 01848 if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) || 01849 ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) || 01850 (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) { 01851 if (!final) { 01852 dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); 01853 } 01854 break; 01855 } 01856 apply_peer(trans, peer); 01857 /* Key passed, use new contexts for this session */ 01858 trans->ecx = peer->them_ecx; 01859 trans->dcx = peer->them_dcx; 01860 } 01861 if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) { 01862 struct dundi_hdr *dhdr; 01863 unsigned char decoded[MAX_PACKET_SIZE]; 01864 int ddatalen; 01865 ddatalen = sizeof(decoded); 01866 dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen); 01867 if (dhdr) { 01868 /* Handle decrypted response */ 01869 if (dundidebug) 01870 dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr)); 01871 handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1); 01872 /* Carry back final flag */ 01873 hdr->cmdresp |= dhdr->cmdresp & 0x80; 01874 break; 01875 } else { 01876 ast_debug(1, "Ouch, decrypt failed :(\n"); 01877 } 01878 } 01879 } 01880 if (!final) { 01881 /* Turn off encryption */ 01882 ast_clear_flag(trans, FLAG_ENCRYPT); 01883 dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); 01884 } 01885 break; 01886 default: 01887 /* Send unknown command if we don't know it, with final flag IFF it's the 01888 first command in the dialog and only if we haven't received final notification */ 01889 if (!final) { 01890 dundi_ie_append_byte(ied, DUNDI_IE_UNKNOWN, cmd); 01891 dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, ied); 01892 } 01893 } 01894 01895 retval = 0; 01896 01897 return_cleanup: 01898 #ifdef LOW_MEMORY 01899 ast_free(ied); 01900 #endif 01901 return retval; 01902 }
| static int handle_frame | ( | struct dundi_hdr * | h, | |
| struct sockaddr_in * | sin, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 1937 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.
01938 { 01939 struct dundi_transaction *trans; 01940 trans = find_transaction(h, sin); 01941 if (!trans) { 01942 dundi_reject(h, sin); 01943 return 0; 01944 } 01945 /* Got a transaction, see where this header fits in */ 01946 if (h->oseqno == trans->iseqno) { 01947 /* Just what we were looking for... Anything but ack increments iseqno */ 01948 if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) { 01949 /* If final, we're done */ 01950 destroy_trans(trans, 0); 01951 return 0; 01952 } 01953 if (h->cmdresp != DUNDI_COMMAND_ACK) { 01954 trans->oiseqno = trans->iseqno; 01955 trans->iseqno++; 01956 handle_command_response(trans, h, datalen, 0); 01957 } 01958 if (trans->aseqno != trans->iseqno) { 01959 dundi_ack(trans, h->cmdresp & 0x80); 01960 trans->aseqno = trans->iseqno; 01961 } 01962 /* Delete any saved last transmissions */ 01963 destroy_packets(&trans->lasttrans); 01964 if (h->cmdresp & 0x80) { 01965 /* Final -- destroy now */ 01966 destroy_trans(trans, 0); 01967 } 01968 } else if (h->oseqno == trans->oiseqno) { 01969 /* Last incoming sequence number -- send ACK without processing */ 01970 dundi_ack(trans, 0); 01971 } else { 01972 /* Out of window -- simply drop */ 01973 ast_debug(1, "Dropping packet out of window!\n"); 01974 } 01975 return 0; 01976 }
| static int has_permission | ( | struct permissionlist * | permlist, | |
| char * | cont | |||
| ) | [static] |
Definition at line 281 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().
00282 { 00283 struct permission *perm; 00284 int res = 0; 00285 00286 AST_LIST_TRAVERSE(permlist, perm, list) { 00287 if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont)) 00288 res = perm->allow; 00289 } 00290 00291 return res; 00292 }
| static int load_module | ( | void | ) | [static] |
Definition at line 4770 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_FAILURE, 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().
04771 { 04772 struct sockaddr_in sin; 04773 04774 dundi_set_output(dundi_debug_output); 04775 dundi_set_error(dundi_error_output); 04776 04777 sin.sin_family = AF_INET; 04778 sin.sin_port = ntohs(DUNDI_PORT); 04779 sin.sin_addr.s_addr = INADDR_ANY; 04780 04781 /* Make a UDP socket */ 04782 io = io_context_create(); 04783 sched = sched_context_create(); 04784 04785 if (!io || !sched) 04786 return AST_MODULE_LOAD_FAILURE; 04787 04788 if (set_config("dundi.conf", &sin, 0)) 04789 return AST_MODULE_LOAD_DECLINE; 04790 04791 netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 04792 04793 if (netsocket < 0) { 04794 ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); 04795 return AST_MODULE_LOAD_FAILURE; 04796 } 04797 if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) { 04798 ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", 04799 ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno)); 04800 return AST_MODULE_LOAD_FAILURE; 04801 } 04802 04803 ast_netsock_set_qos(netsocket, tos, 0, "DUNDi"); 04804 04805 if (start_network_thread()) { 04806 ast_log(LOG_ERROR, "Unable to start network thread\n"); 04807 close(netsocket); 04808 return AST_MODULE_LOAD_FAILURE; 04809 } 04810 04811 ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); 04812 if (ast_register_switch(&dundi_switch)) 04813 ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); 04814 ast_custom_function_register(&dundi_function); 04815 ast_custom_function_register(&dundi_query_function); 04816 ast_custom_function_register(&dundi_result_function); 04817 04818 ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); 04819 04820 return AST_MODULE_LOAD_SUCCESS; 04821 }
| static void load_password | ( | void | ) | [static] |
Definition at line 2034 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().
02035 { 02036 char *current=NULL; 02037 char *last=NULL; 02038 char tmp[256]; 02039 time_t expired; 02040 02041 ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp)); 02042 if (!ast_get_time_t(tmp, &expired, 0, NULL)) { 02043 ast_db_get(secretpath, "secret", tmp, sizeof(tmp)); 02044 current = strchr(tmp, ';'); 02045 if (!current) 02046 current = tmp; 02047 else { 02048 *current = '\0'; 02049 current++; 02050 }; 02051 if ((time(NULL) - expired) < 0) { 02052 if ((expired - time(NULL)) > DUNDI_SECRET_TIME) 02053 expired = time(NULL) + DUNDI_SECRET_TIME; 02054 } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) { 02055 last = current; 02056 current = NULL; 02057 } else { 02058 last = NULL; 02059 current = NULL; 02060 } 02061 } 02062 if (current) { 02063 /* Current key is still valid, just setup rotatation properly */ 02064 ast_copy_string(cursecret, current, sizeof(cursecret)); 02065 rotatetime = expired; 02066 } else { 02067 /* Current key is out of date, rotate or eliminate all together */ 02068 build_secret(cursecret, sizeof(cursecret)); 02069 save_secret(cursecret, last); 02070 } 02071 }
| static void mark_mappings | ( | void | ) | [static] |
Definition at line 4081 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().
04082 { 04083 struct dundi_mapping *map; 04084 04085 AST_LIST_LOCK(&peers); 04086 AST_LIST_TRAVERSE(&mappings, map, list) { 04087 map->dead = 1; 04088 } 04089 AST_LIST_UNLOCK(&peers); 04090 }
| static void mark_peers | ( | void | ) | [static] |
Definition at line 4071 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().
04072 { 04073 struct dundi_peer *peer; 04074 AST_LIST_LOCK(&peers); 04075 AST_LIST_TRAVERSE(&peers, peer, list) { 04076 peer->dead = 1; 04077 } 04078 AST_LIST_UNLOCK(&peers); 04079 }
| static char* model2str | ( | int | model | ) | [static] |
Definition at line 2293 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().
02294 { 02295 switch(model) { 02296 case DUNDI_MODEL_INBOUND: 02297 return "Inbound"; 02298 case DUNDI_MODEL_OUTBOUND: 02299 return "Outbound"; 02300 case DUNDI_MODEL_SYMMETRIC: 02301 return "Symmetric"; 02302 default: 02303 return "Unknown"; 02304 } 02305 }
| static void* network_thread | ( | void * | ignore | ) | [static] |
Definition at line 2090 of file pbx_dundi.c.
References ast_io_add(), AST_IO_IN, ast_io_wait(), AST_LIST_LOCK, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_sched_runq(), ast_sched_wait(), check_password(), and socket_read().
02091 { 02092 /* Our job is simple: Send queued messages, retrying if necessary. Read frames 02093 from the network, and queue them for delivery to the channels */ 02094 int res; 02095 /* Establish I/O callback for socket read */ 02096 ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL); 02097 02098 while (!dundi_shutdown) { 02099 res = ast_sched_wait(sched); 02100 if ((res > 1000) || (res < 0)) 02101 res = 1000; 02102 res = ast_io_wait(io, res); 02103 if (res >= 0) { 02104 AST_LIST_LOCK(&peers); 02105 ast_sched_runq(sched); 02106 AST_LIST_UNLOCK(&peers); 02107 } 02108 check_password(); 02109 } 02110 02111 netthreadid = AST_PTHREADT_NULL; 02112 02113 return NULL; 02114 }
| static int optimize_transactions | ( | struct dundi_request * | dr, | |
| int | order | |||
| ) | [static] |
Definition at line 3261 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::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().
03262 { 03263 /* Minimize the message propagation through DUNDi by 03264 alerting the network to hops which should be not be considered */ 03265 struct dundi_transaction *trans; 03266 struct dundi_peer *peer; 03267 dundi_eid tmp; 03268 int x; 03269 int needpush; 03270 03271 AST_LIST_LOCK(&peers); 03272 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03273 /* Pop off the true root */ 03274 if (trans->eidcount) { 03275 tmp = trans->eids[--trans->eidcount]; 03276 needpush = 1; 03277 } else { 03278 tmp = trans->us_eid; 03279 needpush = 0; 03280 } 03281 03282 AST_LIST_TRAVERSE(&peers, peer, list) { 03283 if (has_permission(&peer->include, dr->dcontext) && 03284 ast_eid_cmp(&peer->eid, &trans->them_eid) && 03285 (peer->order <= order)) { 03286 /* For each other transaction, make sure we don't 03287 ask this EID about the others if they're not 03288 already in the list */ 03289 if (!ast_eid_cmp(&tmp, &peer->eid)) 03290 x = -1; 03291 else { 03292 for (x=0;x<trans->eidcount;x++) { 03293 if (!ast_eid_cmp(&trans->eids[x], &peer->eid)) 03294 break; 03295 } 03296 } 03297 if (x == trans->eidcount) { 03298 /* Nope not in the list, if needed, add us at the end since we're the source */ 03299 if (trans->eidcount < DUNDI_MAX_STACK - needpush) { 03300 trans->eids[trans->eidcount++] = peer->eid; 03301 /* Need to insert the real root (or us) at the bottom now as 03302 a requirement now. */ 03303 needpush = 1; 03304 } 03305 } 03306 } 03307 } 03308 /* If necessary, push the true root back on the end */ 03309 if (needpush) 03310 trans->eids[trans->eidcount++] = tmp; 03311 } 03312 AST_LIST_UNLOCK(&peers); 03313 03314 return 0; 03315 }
| static void populate_addr | ( | struct dundi_peer * | peer, | |
| dundi_eid * | eid | |||
| ) | [static] |
Definition at line 4294 of file pbx_dundi.c.
References dundi_peer::addr, ast_db_get(), ast_eid_to_str(), ast_sched_add(), do_register_expire(), inet_aton(), and dundi_peer::registerexpire.
Referenced by build_peer().
04295 { 04296 char data[256]; 04297 char *c; 04298 int port, expire; 04299 char eid_str[20]; 04300 ast_eid_to_str(eid_str, sizeof(eid_str), eid); 04301 if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) { 04302 c = strchr(data, ':'); 04303 if (c) { 04304 *c = '\0'; 04305 c++; 04306 if (sscanf(c, "%5d:%30d", &port, &expire) == 2) { 04307 /* Got it! */ 04308 inet_aton(data, &peer->addr.sin_addr); 04309 peer->addr.sin_family = AF_INET; 04310 peer->addr.sin_port = htons(port); 04311 peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); 04312 } 04313 } 04314 } 04315 }
| static int precache_trans | ( | struct dundi_transaction * | trans, | |
| struct dundi_mapping * | maps, | |||
| int | mapcount, | |||
| int * | minexp, | |||
| int * | foundanswers | |||
| ) | [static] |
Definition at line 3114 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().
03115 { 03116 struct dundi_ie_data ied; 03117 int x, res; 03118 int max = 999999; 03119 int expiration = dundi_cache_time; 03120 int ouranswers=0; 03121 dundi_eid *avoid[1] = { NULL, }; 03122 int direct[1] = { 0, }; 03123 struct dundi_result dr[MAX_RESULTS]; 03124 struct dundi_hint_metadata hmd; 03125 if (!trans->parent) { 03126 ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); 03127 return -1; 03128 } 03129 memset(&hmd, 0, sizeof(hmd)); 03130 memset(&dr, 0, sizeof(dr)); 03131 /* Look up the answers we're going to include */ 03132 for (x=0;x<mapcount;x++) 03133 ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd); 03134 if (ouranswers < 0) 03135 ouranswers = 0; 03136 for (x=0;x<ouranswers;x++) { 03137 if (dr[x].weight < max) 03138 max = dr[x].weight; 03139 } 03140 if (max) { 03141 /* If we do not have a canonical result, keep looking */ 03142 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); 03143 if (res > 0) { 03144 /* Append answer in result */ 03145 ouranswers += res; 03146 } 03147 } 03148 03149 if (ouranswers > 0) { 03150 *foundanswers += ouranswers; 03151 memset(&ied, 0, sizeof(ied)); 03152 dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); 03153 if (!dundi_eid_zero(&trans->us_eid)) 03154 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); 03155 for (x=0;x<trans->eidcount;x++) 03156 dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); 03157 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); 03158 dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); 03159 dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); 03160 for (x=0;x<ouranswers;x++) { 03161 /* Add answers */ 03162 if (dr[x].expiration && (expiration > dr[x].expiration)) 03163 expiration = dr[x].expiration; 03164 dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); 03165 } 03166 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); 03167 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); 03168 if (trans->autokilltimeout) 03169 trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); 03170 if (expiration < *minexp) 03171 *minexp = expiration; 03172 return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied); 03173 } else { 03174 /* Oops, nothing to send... */ 03175 destroy_trans(trans, 0); 03176 return 0; 03177 } 03178 }
| static int precache_transactions | ( | struct dundi_request * | dr, | |
| struct dundi_mapping * | maps, | |||
| int | mapcount, | |||
| int * | expiration, | |||
| int * | foundanswers | |||
| ) | [static] |
Definition at line 3213 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().
03214 { 03215 struct dundi_transaction *trans; 03216 03217 /* Mark all as "in thread" so they don't disappear */ 03218 AST_LIST_LOCK(&peers); 03219 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03220 if (trans->thread) 03221 ast_log(LOG_WARNING, "This shouldn't happen, really...\n"); 03222 trans->thread = 1; 03223 } 03224 AST_LIST_UNLOCK(&peers); 03225 03226 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03227 if (!ast_test_flag(trans, FLAG_DEAD)) 03228 precache_trans(trans, maps, mapcount, expiration, foundanswers); 03229 } 03230 03231 /* Cleanup any that got destroyed in the mean time */ 03232 AST_LIST_LOCK(&peers); 03233 AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) { 03234 trans->thread = 0; 03235 if (ast_test_flag(trans, FLAG_DEAD)) { 03236 ast_debug(1, "Our transaction went away!\n"); 03237 /* This is going to remove the transaction from the dundi_request's list, as well 03238 * as the global transactions list */ 03239 destroy_trans(trans, 0); 03240 } 03241 } 03242 AST_LIST_TRAVERSE_SAFE_END 03243 AST_LIST_UNLOCK(&peers); 03244 03245 return 0; 03246 }
| static void* process_clearcache | ( | void * | ignore | ) | [static] |
Definition at line 2116 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().
02117 { 02118 struct ast_db_entry *db_entry, *db_tree; 02119 int striplen = sizeof("/dundi/cache"); 02120 time_t now; 02121 02122 while (!dundi_shutdown) { 02123 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 02124 02125 time(&now); 02126 02127 db_entry = db_tree = ast_db_gettree("dundi/cache", NULL); 02128 for (; db_entry; db_entry = db_entry->next) { 02129 time_t expiry; 02130 02131 if (!ast_get_time_t(db_entry->data, &expiry, 0, NULL)) { 02132 if (expiry < now) { 02133 ast_debug(1, "clearing expired DUNDI cache entry: %s\n", db_entry->key); 02134 ast_db_del("dundi/cache", db_entry->key + striplen); 02135 } 02136 } 02137 } 02138 ast_db_freetree(db_tree); 02139 02140 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 02141 pthread_testcancel(); 02142 sleep(60); 02143 pthread_testcancel(); 02144 } 02145 02146 clearcachethreadid = AST_PTHREADT_NULL; 02147 return NULL; 02148 }
| static void* process_precache | ( | void * | ign | ) | [static] |
Definition at line 2150 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().
02151 { 02152 struct dundi_precache_queue *qe; 02153 time_t now; 02154 char context[256]; 02155 char number[256]; 02156 int run; 02157 02158 while (!dundi_shutdown) { 02159 time(&now); 02160 run = 0; 02161 AST_LIST_LOCK(&pcq); 02162 if ((qe = AST_LIST_FIRST(&pcq))) { 02163 if (!qe->expiration) { 02164 /* Gone... Remove... */ 02165 AST_LIST_REMOVE_HEAD(&pcq, list); 02166 ast_free(qe); 02167 } else if (qe->expiration < now) { 02168 /* Process this entry */ 02169 qe->expiration = 0; 02170 ast_copy_string(context, qe->context, sizeof(context)); 02171 ast_copy_string(number, qe->number, sizeof(number)); 02172 run = 1; 02173 } 02174 } 02175 AST_LIST_UNLOCK(&pcq); 02176 if (run) { 02177 dundi_precache(context, number); 02178 } else 02179 sleep(1); 02180 } 02181 02182 precachethreadid = AST_PTHREADT_NULL; 02183 02184 return NULL; 02185 }
| static void prune_mappings | ( | void | ) | [static] |
Definition at line 4133 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().
04134 { 04135 struct dundi_mapping *map; 04136 04137 AST_LIST_LOCK(&peers); 04138 AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) { 04139 if (map->dead) { 04140 AST_LIST_REMOVE_CURRENT(list); 04141 destroy_map(map); 04142 } 04143 } 04144 AST_LIST_TRAVERSE_SAFE_END; 04145 AST_LIST_UNLOCK(&peers); 04146 }
| static void prune_peers | ( | void | ) | [static] |
Definition at line 4118 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().
04119 { 04120 struct dundi_peer *peer; 04121 04122 AST_LIST_LOCK(&peers); 04123 AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) { 04124 if (peer->dead) { 04125 AST_LIST_REMOVE_CURRENT(list); 04126 destroy_peer(peer); 04127 } 04128 } 04129 AST_LIST_TRAVERSE_SAFE_END; 04130 AST_LIST_UNLOCK(&peers); 04131 }
| static void qualify_peer | ( | struct dundi_peer * | peer, | |
| int | schedonly | |||
| ) | [static] |
Definition at line 4271 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().
04272 { 04273 int when; 04274 AST_SCHED_DEL(sched, peer->qualifyid); 04275 if (peer->qualtrans) 04276 destroy_trans(peer->qualtrans, 0); 04277 peer->qualtrans = NULL; 04278 if (peer->maxms > 0) { 04279 when = 60000; 04280 if (peer->lastms < 0) 04281 when = 10000; 04282 if (schedonly) 04283 when = 5000; 04284 peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer); 04285 if (!schedonly) 04286 peer->qualtrans = create_transaction(peer); 04287 if (peer->qualtrans) { 04288 peer->qualtx = ast_tvnow(); 04289 ast_set_flag(peer->qualtrans, FLAG_ISQUAL); 04290 dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL); 04291 } 04292 } 04293 }
| static int query_transactions | ( | struct dundi_request * | dr | ) | [static] |
Definition at line 3248 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().
03249 { 03250 struct dundi_transaction *trans; 03251 03252 AST_LIST_LOCK(&peers); 03253 AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) { 03254 dundi_query(trans); 03255 } 03256 AST_LIST_UNLOCK(&peers); 03257 03258 return 0; 03259 }
| static int register_request | ( | struct dundi_request * | dr, | |
| struct dundi_request ** | pending | |||
| ) | [static] |
Definition at line 3432 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().
03433 { 03434 struct dundi_request *cur; 03435 int res=0; 03436 char eid_str[20]; 03437 AST_LIST_LOCK(&peers); 03438 AST_LIST_TRAVERSE(&requests, cur, list) { 03439 ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number, 03440 dr->dcontext, dr->number); 03441 if (!strcasecmp(cur->dcontext, dr->dcontext) && 03442 !strcasecmp(cur->number, dr->number) && 03443 (!ast_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) { 03444 ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08x'\n", 03445 cur->dcontext, cur->number, ast_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32); 03446 *pending = cur; 03447 res = 1; 03448 break; 03449 } 03450 } 03451 if (!res) { 03452 ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08x'\n", 03453 dr->number, dr->dcontext, ast_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32); 03454 /* Go ahead and link us in since nobody else is searching for this */ 03455 AST_LIST_INSERT_HEAD(&requests, dr, list); 03456 *pending = NULL; 03457 } 03458 AST_LIST_UNLOCK(&peers); 03459 return res; 03460 }
| static int reload | ( | void | ) | [static] |
Definition at line 4760 of file pbx_dundi.c.
References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and set_config().
04761 { 04762 struct sockaddr_in sin; 04763 04764 if (set_config("dundi.conf", &sin, 1)) 04765 return AST_MODULE_LOAD_FAILURE; 04766 04767 return AST_MODULE_LOAD_SUCCESS; 04768 }
| static void reschedule_precache | ( | const char * | number, | |
| const char * | context, | |||
| int | expiration | |||
| ) | [static] |
Definition at line 3611 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().
03612 { 03613 int len; 03614 struct dundi_precache_queue *qe, *prev; 03615 03616 AST_LIST_LOCK(&pcq); 03617 AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) { 03618 if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) { 03619 AST_LIST_REMOVE_CURRENT(list); 03620 break; 03621 } 03622 } 03623 AST_LIST_TRAVERSE_SAFE_END; 03624 if (!qe) { 03625 len = sizeof(*qe); 03626 len += strlen(number) + 1; 03627 len += strlen(context) + 1; 03628 if (!(qe = ast_calloc(1, len))) { 03629 AST_LIST_UNLOCK(&pcq); 03630 return; 03631 } 03632 strcpy(qe->number, number); 03633 qe->context = qe->number + strlen(number) + 1; 03634 strcpy(qe->context, context); 03635 } 03636 time(&qe->expiration); 03637 qe->expiration += expiration; 03638 if ((prev = AST_LIST_FIRST(&pcq))) { 03639 while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->