Thu Apr 28 2011 17:13:43

Asterisk developer's documentation


chan_iax2.c File Reference

Implementation of Inter-Asterisk eXchange Version 2 as specified in RFC 5456. More...

#include "asterisk.h"
#include <sys/mman.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <signal.h>
#include <strings.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <regex.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/frame.h"
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/translate.h"
#include "asterisk/md5.h"
#include "asterisk/cdr.h"
#include "asterisk/crypto.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
#include "asterisk/app.h"
#include "asterisk/astdb.h"
#include "asterisk/musiconhold.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/localtime.h"
#include "asterisk/aes.h"
#include "asterisk/dnsmgr.h"
#include "asterisk/devicestate.h"
#include "asterisk/netsock.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/event.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "iax2.h"
#include "iax2-parser.h"
#include "iax2-provision.h"
#include "jitterbuf.h"

Go to the source code of this file.

Data Structures

struct  active_list
struct  addr_range
struct  callno_entry
struct  chan_iax2_pvt
struct  create_addr_info
struct  dpcache
struct  dpreq_data
struct  dynamic_list
struct  firmwares
struct  frame_queue
 a list of frames that may need to be retransmitted More...
struct  iax2_context
struct  iax2_dpcache
struct  iax2_peer
struct  iax2_pkt_buf
struct  iax2_registry
struct  iax2_thread
struct  iax2_trunk_peer
struct  iax2_user
struct  iax_dual
struct  iax_firmware
struct  iax_rr
struct  idle_list
struct  parsed_dial_string
struct  peercnt
struct  registrations
struct  chan_iax2_pvt::signaling_queue
struct  signaling_queue_entry
struct  tpeers

Defines

#define ACN_FORMAT1   "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
#define ACN_FORMAT2   "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
#define CALLNO_TO_PTR(a)   ((void *)(unsigned long)(a))
#define CALLTOKEN_HASH_FORMAT   "%s%d%u%d"
#define CALLTOKEN_IE_FORMAT   "%u?%s"
#define DEBUG_SCHED_MULTITHREAD
#define DEBUG_SUPPORT
#define DEFAULT_CONTEXT   "default"
#define DEFAULT_DROP   3
#define DEFAULT_FREQ_NOTOK   10 * 1000
#define DEFAULT_FREQ_OK   60 * 1000
#define DEFAULT_MAX_THREAD_COUNT   100
#define DEFAULT_MAXMS   2000
#define DEFAULT_RETRY_TIME   1000
#define DEFAULT_THREAD_COUNT   10
#define DEFAULT_TRUNKDATA   640 * 10
#define FORMAT   "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s %-5.10s\n"
#define FORMAT   "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s%s"
#define FORMAT   "%-20.20s %-6.6s %-10.10s %-20.20s %8d %s\n"
#define FORMAT   "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-4.4dms %-6.6s %s%s %3s%s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s %s %9s\n"
#define FORMAT2   "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s %-5.10s\n"
#define FORMAT2   "%-20.20s %-6.6s %-10.10s %-20.20s %8.8s %s\n"
#define FORMAT2   "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s%s"
#define FORMATB   "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d [Native Bridged to ID=%5.5d]\n"
#define GAMMA   (0.01)
#define IAX2_TRUNK_PREFACE   (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
#define IAX_CALLENCRYPTED(pvt)   (ast_test_flag(pvt, IAX_ENCRYPTED) && ast_test_flag(pvt, IAX_KEYPOPULATED))
#define IAX_CAPABILITY_FULLBANDWIDTH   0xFFFF
#define IAX_CAPABILITY_LOWBANDWIDTH
#define IAX_CAPABILITY_LOWFREE
#define IAX_CAPABILITY_MEDBANDWIDTH
#define IAX_DEBUGDIGEST(msg, key)
#define MARK_IAX_SUBCLASS_TX   0x8000
#define MAX_JITTER_BUFFER   50
#define MAX_PEER_BUCKETS   563
#define MAX_RETRY_TIME   10000
#define MAX_TIMESTAMP_SKEW   160
#define MAX_TRUNK_MTU   1240
 Maximum transmission unit for the UDP packet in the trunk not to be fragmented. This is based on 1516 - ethernet - ip - udp - iax minus one g711 frame = 1240.
#define MAX_TRUNKDATA   640 * 200
#define MAX_USER_BUCKETS   MAX_PEER_BUCKETS
#define MEMORY_SIZE   100
#define MIN_JITTER_BUFFER   10
#define MIN_RETRY_TIME   100
#define MIN_REUSE_TIME   60
#define PTR_TO_CALLNO(a)   ((unsigned short)(unsigned long)(a))
#define SCHED_MULTITHREADED
#define schedule_action(func, data)   __schedule_action(func, data, __PRETTY_FUNCTION__)
#define TRUNK_CALL_START   IAX_MAX_CALLS / 2
#define TS_GAP_FOR_JB_RESYNC   5000

Enumerations

enum  {
  CACHE_FLAG_EXISTS = (1 << 0), CACHE_FLAG_NONEXISTENT = (1 << 1), CACHE_FLAG_CANEXIST = (1 << 2), CACHE_FLAG_PENDING = (1 << 3),
  CACHE_FLAG_TIMEOUT = (1 << 4), CACHE_FLAG_TRANSMITTED = (1 << 5), CACHE_FLAG_UNKNOWN = (1 << 6), CACHE_FLAG_MATCHMORE = (1 << 7)
}
enum  { NEW_PREVENT = 0, NEW_ALLOW = 1, NEW_FORCE = 2, NEW_ALLOW_CALLTOKEN_VALIDATED = 3 }
enum  calltoken_peer_enum { CALLTOKEN_DEFAULT = 0, CALLTOKEN_YES = 1, CALLTOKEN_AUTO = 2, CALLTOKEN_NO = 3 }
 

Call token validation settings.

More...
enum  iax2_flags {
  IAX_HASCALLERID = (1 << 0), IAX_DELME = (1 << 1), IAX_TEMPONLY = (1 << 2), IAX_TRUNK = (1 << 3),
  IAX_NOTRANSFER = (1 << 4), IAX_USEJITTERBUF = (1 << 5), IAX_DYNAMIC = (1 << 6), IAX_SENDANI = (1 << 7),
  IAX_ALREADYGONE = (1 << 9), IAX_PROVISION = (1 << 10), IAX_QUELCH = (1 << 11), IAX_ENCRYPTED = (1 << 12),
  IAX_KEYPOPULATED = (1 << 13), IAX_CODEC_USER_FIRST = (1 << 14), IAX_CODEC_NOPREFS = (1 << 15), IAX_CODEC_NOCAP = (1 << 16),
  IAX_RTCACHEFRIENDS = (1 << 17), IAX_RTUPDATE = (1 << 18), IAX_RTAUTOCLEAR = (1 << 19), IAX_FORCEJITTERBUF = (1 << 20),
  IAX_RTIGNOREREGEXPIRE = (1 << 21), IAX_TRUNKTIMESTAMPS = (1 << 22), IAX_TRANSFERMEDIA = (1 << 23), IAX_MAXAUTHREQ = (1 << 24),
  IAX_DELAYPBXSTART = (1 << 25), IAX_ALLOWFWDOWNLOAD = (1 << 26), IAX_IMMEDIATE = (1 << 27), IAX_FORCE_ENCRYPT = (1 << 28),
  IAX_SHRINKCALLERID = (1 << 29)
}
enum  iax2_state { IAX_STATE_STARTED = (1 << 0), IAX_STATE_AUTHENTICATED = (1 << 1), IAX_STATE_TBD = (1 << 2) }
enum  iax2_thread_iostate { IAX_IOSTATE_IDLE, IAX_IOSTATE_READY, IAX_IOSTATE_PROCESSING, IAX_IOSTATE_SCHEDREADY }
enum  iax2_thread_type { IAX_THREAD_TYPE_POOL, IAX_THREAD_TYPE_DYNAMIC }
enum  iax_reg_state {
  REG_STATE_UNREGISTERED = 0, REG_STATE_REGSENT, REG_STATE_AUTHSENT, REG_STATE_REGISTERED,
  REG_STATE_REJECTED, REG_STATE_TIMEOUT, REG_STATE_NOAUTH
}
enum  iax_transfer_state {
  TRANSFER_NONE = 0, TRANSFER_BEGIN, TRANSFER_READY, TRANSFER_RELEASED,
  TRANSFER_PASSTHROUGH, TRANSFER_MBEGIN, TRANSFER_MREADY, TRANSFER_MRELEASED,
  TRANSFER_MPASSTHROUGH, TRANSFER_MEDIA, TRANSFER_MEDIAPASS
}

Functions

static void __attempt_transmit (const void *data)
static void __auth_reject (const void *nothing)
static void __auto_congest (const void *nothing)
static void __auto_hangup (const void *nothing)
static int __do_deliver (void *data)
static void __expire_registry (const void *data)
static int __find_callno (unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
static void __get_from_jb (const void *p)
static void __iax2_do_register_s (const void *data)
static void __iax2_poke_noanswer (const void *data)
static void __iax2_poke_peer_s (const void *data)
static int __iax2_show_peers (int manager, int fd, struct mansession *s, int argc, char *argv[])
static void __reg_module (void)
static int __schedule_action (void(*func)(const void *data), const void *data, const char *funcname)
static int __send_command (struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno, int now, int transfer, int final)
static void __send_lagrq (const void *data)
static void __send_ping (const void *data)
static int __unload_module (void)
static void __unreg_module (void)
static int acf_channel_read (struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
static int acf_iaxvar_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_iaxvar_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int add_calltoken_ignore (const char *addr)
static void add_empty_calltoken_ie (struct chan_iax2_pvt *pvt, struct iax_ie_data *ied)
static int addr_range_cmp_cb (void *obj, void *arg, int flags)
static int addr_range_delme_cb (void *obj, void *arg, int flags)
static int addr_range_hash_cb (const void *obj, const int flags)
static int addr_range_match_address_cb (void *obj, void *arg, int flags)
static int apply_context (struct iax2_context *con, const char *context)
static int ast_cli_netstats (struct mansession *s, int fd, int limit_fmt)
static struct ast_channelast_iax2_new (int callno, int state, int capability)
 Create new call, interface with the PBX core.
static int attempt_transmit (const void *data)
static int auth_fail (int callno, int failcode)
static int auth_reject (const void *data)
static int authenticate (const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, struct chan_iax2_pvt *pvt)
static int authenticate_reply (struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
static int authenticate_request (int call_num)
static int authenticate_verify (struct chan_iax2_pvt *p, struct iax_ies *ies)
static int auto_congest (const void *data)
static int auto_hangup (const void *data)
static void build_callno_limits (struct ast_variable *v)
static struct iax2_contextbuild_context (const char *context)
static void build_ecx_key (const unsigned char *digest, struct chan_iax2_pvt *pvt)
static void build_encryption_keys (const unsigned char *digest, struct chan_iax2_pvt *pvt)
static struct iax2_peerbuild_peer (const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 Create peer structure based on configuration.
static void build_rand_pad (unsigned char *buf, ssize_t len)
static struct iax2_userbuild_user (const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 Create in-memory user structure from configuration.
static int cache_get_callno_locked (const char *data)
static unsigned int calc_rxstamp (struct chan_iax2_pvt *p, unsigned int offset)
static unsigned int calc_timestamp (struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f)
static unsigned int calc_txpeerstamp (struct iax2_trunk_peer *tpeer, int sampms, struct timeval *now)
static int callno_hash (const void *obj, const int flags)
static int calltoken_required (struct sockaddr_in *sin, const char *name, int subclass)
static int check_access (int callno, struct sockaddr_in *sin, struct iax_ies *ies)
static int check_provisioning (struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
static int check_srcaddr (struct sockaddr *sa, socklen_t salen)
 Check if address can be used as packet source.
static void cleanup_thread_list (void *head)
static int complete_dpreply (struct chan_iax2_pvt *pvt, struct iax_ies *ies)
static char * complete_iax2_peers (const char *line, const char *word, int pos, int state, int flags)
static char * complete_iax2_unregister (const char *line, const char *word, int pos, int state)
static int complete_transfer (int callno, struct iax_ies *ies)
static unsigned char compress_subclass (int subclass)
static void construct_rr (struct chan_iax2_pvt *pvt, struct iax_ie_data *iep)
static int create_addr (const char *peername, struct ast_channel *c, struct sockaddr_in *sin, struct create_addr_info *cai)
static int create_callno_pools (void)
static int decode_frame (ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
static int decrypt_frame (int callno, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
static void defer_full_frame (struct iax2_thread *from_here, struct iax2_thread *to_here)
 Queue the last read full frame for processing by a certain thread.
static void delete_users (void)
static void destroy_firmware (struct iax_firmware *cur)
static void dp_lookup (int callno, const char *context, const char *callednum, const char *callerid, int skiplock)
static void * dp_lookup_thread (void *data)
static void encmethods_to_str (int e, struct ast_str *buf)
static int encrypt_frame (ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh, unsigned char *poo, int *datalen)
static int expire_registry (const void *data)
static struct iax2_dpcachefind_cache (struct ast_channel *chan, const char *data, const char *context, const char *exten, int priority)
static int find_callno (unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame)
static int find_callno_locked (unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame)
static struct iax2_threadfind_idle_thread (void)
static struct iax2_peerfind_peer (const char *name, int realtime)
static struct iax2_trunk_peerfind_tpeer (struct sockaddr_in *sin, int fd)
static struct iax2_userfind_user (const char *name)
static unsigned int fix_peerts (struct timeval *rxtrunktime, int callno, unsigned int ts)
static void free_context (struct iax2_context *con)
static void free_signaling_queue_entry (struct signaling_queue_entry *s)
static int function_iaxpeer (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int get_auth_methods (const char *value)
static int get_encrypt_methods (const char *s)
static int get_from_jb (const void *p)
static struct callno_entryget_unused_callno (int trunk, int validated)
static int handle_call_token (struct ast_iax2_full_hdr *fh, struct iax_ies *ies, struct sockaddr_in *sin, int fd)
static char * handle_cli_iax2_provision (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_prune_realtime (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_set_debug_jb (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_set_debug_trunk (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_set_mtu (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Set trunk MTU from CLI.
static char * handle_cli_iax2_show_cache (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_callno_limits (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_firmware (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_netstats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_peer (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show one peer in detail.
static char * handle_cli_iax2_show_peers (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_registry (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_threads (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_show_users (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_test_losspct (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_iax2_unregister (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_deferred_full_frames (struct iax2_thread *thread)
 Handle any deferred full frames for this thread.
static int handle_error (void)
static int iax2_ack_registry (struct iax_ies *ies, struct sockaddr_in *sin, int callno)
 Acknowledgment received for OUR registration.
static int attribute_pure iax2_allow_new (int frametype, int subclass, int inbound)
static void iax2_ami_channelupdate (struct chan_iax2_pvt *pvt)
 Send manager event at call setup to link between Asterisk channel name and IAX2 call identifiers.
static int iax2_answer (struct ast_channel *c)
static int iax2_append_register (const char *hostname, const char *username, const char *secret, const char *porta)
static enum ast_bridge_result iax2_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
static int iax2_call (struct ast_channel *c, char *dest, int timeout)
static int iax2_canmatch (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
 part of the IAX2 dial plan switch interface
static unsigned int iax2_datetime (const char *tz)
static void iax2_destroy (int callno)
static void iax2_destroy_helper (struct chan_iax2_pvt *pvt)
static int iax2_devicestate (void *data)
 Part of the device state notification system ---.
static int iax2_digit_begin (struct ast_channel *c, char digit)
static int iax2_digit_end (struct ast_channel *c, char digit, unsigned int duration)
static int iax2_do_register (struct iax2_registry *reg)
static int iax2_do_register_s (const void *data)
static void iax2_dprequest (struct iax2_dpcache *dp, int callno)
static void * iax2_dup_variable_datastore (void *)
static int iax2_exec (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
 Execute IAX2 dialplan switch.
static int iax2_exists (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
 Part of the IAX2 switch interface.
static int iax2_fixup (struct ast_channel *oldchannel, struct ast_channel *newchan)
static void iax2_frame_free (struct iax_frame *fr)
static void iax2_free_variable_datastore (void *)
static int iax2_getpeername (struct sockaddr_in sin, char *host, int len)
static int iax2_getpeertrunk (struct sockaddr_in sin)
static int iax2_hangup (struct ast_channel *c)
static int iax2_indicate (struct ast_channel *c, int condition, const void *data, size_t datalen)
static int iax2_key_rotate (const void *vpvt)
static void iax2_lock_owner (int callno)
static int iax2_matchmore (struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
 Part of the IAX2 Switch interface.
static int iax2_poke_noanswer (const void *data)
static int iax2_poke_peer (struct iax2_peer *peer, int heldcall)
static int iax2_poke_peer_cb (void *obj, void *arg, int flags)
static int iax2_poke_peer_s (const void *data)
static int iax2_predestroy (int callno)
static void * iax2_process_thread (void *data)
static void iax2_process_thread_cleanup (void *data)
static int iax2_prov_app (struct ast_channel *chan, void *data)
static int iax2_provision (struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force)
static int iax2_queue_control_data (int callno, enum ast_control_frame_type control, const void *data, size_t datalen)
 Queue a control frame on the ast_channel owner.
static int iax2_queue_frame (int callno, struct ast_frame *f)
 Queue a frame to a call's owning asterisk channel.
static int iax2_queue_hangup (int callno)
 Queue a hangup frame on the ast_channel owner.
static struct ast_frameiax2_read (struct ast_channel *c)
static int iax2_register (const char *value, int lineno)
static struct ast_channeliax2_request (const char *type, int format, void *data, int *cause)
static int iax2_sched_add (struct ast_sched_thread *st, int when, ast_sched_cb callback, const void *data)
static int iax2_sched_replace (int id, struct ast_sched_thread *st, int when, ast_sched_cb callback, const void *data)
static int iax2_send (struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
static int iax2_sendhtml (struct ast_channel *c, int subclass, const char *data, int datalen)
static int iax2_sendimage (struct ast_channel *c, struct ast_frame *img)
static int iax2_sendtext (struct ast_channel *c, const char *text)
static int iax2_setoption (struct ast_channel *c, int option, void *data, int datalen)
static int iax2_start_transfer (unsigned short callno0, unsigned short callno1, int mediaonly)
static int iax2_transfer (struct ast_channel *c, const char *dest)
static int iax2_transmit (struct iax_frame *fr)
static int iax2_trunk_expired (struct iax2_trunk_peer *tpeer, struct timeval *now)
static int iax2_trunk_queue (struct chan_iax2_pvt *pvt, struct iax_frame *fr)
static int iax2_vnak (int callno)
static int iax2_write (struct ast_channel *c, struct ast_frame *f)
static int iax_check_version (char *dev)
static void iax_debug_output (const char *data)
static void iax_error_output (const char *data)
static int iax_firmware_append (struct iax_ie_data *ied, const unsigned char *dev, unsigned int desc)
static void iax_outputframe (struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
static int iax_park (struct ast_channel *chan1, struct ast_channel *chan2)
static void * iax_park_thread (void *stuff)
static struct iax_frameiaxfrdup2 (struct iax_frame *fr)
static void insert_idle_thread (struct iax2_thread *thread)
static void jb_debug_output (const char *fmt,...)
static void jb_error_output (const char *fmt,...)
static void jb_warning_output (const char *fmt,...)
static int load_module (void)
 Load IAX2 module, load configuraiton ---.
static int load_objects (void)
static void lock_both (unsigned short callno0, unsigned short callno1)
static void log_jitterstats (unsigned short callno)
static int make_trunk (unsigned short callno, int locked)
static int manager_iax2_show_netstats (struct mansession *s, const struct message *m)
static int manager_iax2_show_peer_list (struct mansession *s, const struct message *m)
 callback to display iax peers in manager format
static int manager_iax2_show_peers (struct mansession *s, const struct message *m)
 callback to display iax peers in manager
static int manager_iax2_show_registry (struct mansession *s, const struct message *m)
static int match (struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
static void memcpy_decrypt (unsigned char *dst, const unsigned char *src, int len, ast_aes_decrypt_key *dcx)
static void memcpy_encrypt (unsigned char *dst, const unsigned char *src, int len, ast_aes_encrypt_key *ecx)
static void merge_encryption (struct chan_iax2_pvt *p, unsigned int enc)
static void mwi_event_cb (const struct ast_event *event, void *userdata)
static void * network_thread (void *ignore)
static struct chan_iax2_pvtnew_iax (struct sockaddr_in *sin, const char *host)
static void parse_dial_string (char *data, struct parsed_dial_string *pds)
 Parses an IAX dial string into its component parts.
static int peer_cmp_cb (void *obj, void *arg, int flags)
static int peer_delme_cb (void *obj, void *arg, int flags)
static void peer_destructor (void *obj)
static int peer_hash_cb (const void *obj, const int flags)
static struct iax2_peerpeer_ref (struct iax2_peer *peer)
static int peer_set_sock_cb (void *obj, void *arg, int flags)
static int peer_set_srcaddr (struct iax2_peer *peer, const char *srcaddr)
 Parse the "sourceaddress" value, lookup in netsock list and set peer's sockfd. Defaults to defaultsockfd if not found.
static int peer_status (struct iax2_peer *peer, char *status, int statuslen)
 peer_status: Report Peer status in character string
static struct iax2_peerpeer_unref (struct iax2_peer *peer)
static int peercnt_add (struct sockaddr_in *sin)
static int peercnt_cmp_cb (void *obj, void *arg, int flags)
static int peercnt_hash_cb (const void *obj, const int flags)
static void peercnt_modify (unsigned char reg, uint16_t limit, struct sockaddr_in *sin)
static void peercnt_remove (struct peercnt *peercnt)
static int peercnt_remove_by_addr (struct sockaddr_in *sin)
static int peercnt_remove_cb (const void *obj)
static void poke_all_peers (void)
static int prune_addr_range_cb (void *obj, void *arg, int flags)
static void prune_peers (void)
static void prune_users (void)
static int pvt_cmp_cb (void *obj, void *arg, int flags)
static void pvt_destructor (void *obj)
static int pvt_hash_cb (const void *obj, const int flags)
static int queue_signalling (struct chan_iax2_pvt *pvt, struct ast_frame *f)
 All frames other than that of type AST_FRAME_IAX must be held until we have received a destination call number.
static int raw_hangup (struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd)
static struct iax2_peerrealtime_peer (const char *peername, struct sockaddr_in *sin)
static void realtime_update_peer (const char *peername, struct sockaddr_in *sin, time_t regtime)
static struct iax2_userrealtime_user (const char *username, struct sockaddr_in *sin)
static void reg_source_db (struct iax2_peer *p)
static void register_peer_exten (struct iax2_peer *peer, int onoff)
static int register_verify (int callno, struct sockaddr_in *sin, struct iax_ies *ies)
 Verify inbound registration.
static int registry_authrequest (int callno)
static int registry_rerequest (struct iax_ies *ies, int callno, struct sockaddr_in *sin)
static char * regstate2str (int regstate)
static int reload (void)
static int reload_config (void)
static void reload_firmware (int unload)
static void remove_by_peercallno (struct chan_iax2_pvt *pvt)
static void remove_by_transfercallno (struct chan_iax2_pvt *pvt)
static int replace_callno (const void *obj)
static void requirecalltoken_mark_auto (const char *name, int subclass)
static void resend_with_token (int callno, struct iax_frame *f, const char *newtoken)
static void save_osptoken (struct iax_frame *fr, struct iax_ies *ies)
static void save_rr (struct iax_frame *fr, struct iax_ies *ies)
static void sched_delay_remove (struct sockaddr_in *sin, struct callno_entry *callno_entry)
static int schedule_delivery (struct iax_frame *fr, int updatehistory, int fromtrunk, unsigned int *tsout)
static int scheduled_destroy (const void *vid)
static int send_apathetic_reply (unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int command, int ts, unsigned char seqno, int sockfd, struct iax_ie_data *ied)
static int send_command (struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int)
static int send_command_final (struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int)
static int send_command_immediate (struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int)
static int send_command_locked (unsigned short callno, char, int, unsigned int, const unsigned char *, int, int)
static int send_command_transfer (struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int)
static int send_lagrq (const void *data)
static int send_packet (struct iax_frame *f)
static int send_ping (const void *data)
static void send_signaling (struct chan_iax2_pvt *pvt)
 This function must be called once we are sure the other side has given us a call number. All signaling is held here until that point.
static int send_trunk (struct iax2_trunk_peer *tpeer, struct timeval *now)
static int set_config (const char *config_file, int reload)
 Load configuration.
static void set_config_destroy (void)
static void set_peercnt_limit (struct peercnt *peercnt)
static int set_peercnt_limit_all_cb (void *obj, void *arg, int flags)
static void signal_condition (ast_mutex_t *lock, ast_cond_t *cond)
static int socket_process (struct iax2_thread *thread)
static int socket_process_meta (int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd, struct iax_frame *fr)
static int socket_read (int *id, int fd, short events, void *cbdata)
static void spawn_dp_lookup (int callno, const char *context, const char *callednum, const char *callerid)
static int start_network_thread (void)
static void stop_stuff (int callno)
static void store_by_peercallno (struct chan_iax2_pvt *pvt)
static void store_by_transfercallno (struct chan_iax2_pvt *pvt)
static int timing_read (int *id, int fd, short events, void *cbdata)
static int transfercallno_pvt_cmp_cb (void *obj, void *arg, int flags)
static int transfercallno_pvt_hash_cb (const void *obj, const int flags)
static int transmit_trunk (struct iax_frame *f, struct sockaddr_in *sin, int sockfd)
static int try_firmware (char *s)
static int try_transfer (struct chan_iax2_pvt *pvt, struct iax_ies *ies)
static int uncompress_subclass (unsigned char csub)
static void unlink_peer (struct iax2_peer *peer)
static int unload_module (void)
static void unlock_both (unsigned short callno0, unsigned short callno1)
static void unwrap_timestamp (struct iax_frame *fr)
static void update_jbsched (struct chan_iax2_pvt *pvt)
static void update_max_nontrunk (void)
static void update_max_trunk (void)
static int update_packet (struct iax_frame *f)
static int update_registry (struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
static int user_cmp_cb (void *obj, void *arg, int flags)
static int user_delme_cb (void *obj, void *arg, int flags)
static void user_destructor (void *obj)
static int user_hash_cb (const void *obj, const int flags)
static struct iax2_useruser_ref (struct iax2_user *user)
static struct iax2_useruser_unref (struct iax2_user *user)
static void vnak_retransmit (int callno, int last)
static int wait_for_peercallno (struct chan_iax2_pvt *pvt)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Inter Asterisk eXchange (Ver 2)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char accountcode [AST_MAX_ACCOUNT_CODE]
static struct active_list active_list
static int adsi = 0
static int amaflags = 0
static struct ast_module_infoast_module_info = &__mod_info
static int authdebug = 1
static int autokill = 0
static struct ao2_containercallno_limits
static struct ao2_containercallno_pool
static const unsigned int CALLNO_POOL_BUCKETS = 2699
static struct ao2_containercallno_pool_trunk
static struct ao2_containercalltoken_ignores
static struct ast_cli_entry cli_iax2 []
static struct sockaddr_in debugaddr
static uint16_t DEFAULT_MAXCALLNO_LIMIT = 2048
static uint16_t DEFAULT_MAXCALLNO_LIMIT_NONVAL = 8192
static char default_parkinglot [AST_MAX_CONTEXT]
static int defaultsockfd = -1
static int delayreject = 0
static struct dpcache dpcache
static struct dynamic_list dynamic_list
static struct firmwares firmwares
static struct frame_queue frame_queue
static int global_max_trunk_mtu
static uint16_t global_maxcallno
static uint16_t global_maxcallno_nonval
static int global_rtautoclear = 120
static struct ast_flags globalflags = { 0 }
static int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH
static int iax2_encryption = 0
int(* iax2_regfunk )(const char *username, int onoff) = NULL
static struct ast_switch iax2_switch
static struct ast_channel_tech iax2_tech
static struct ast_datastore_info iax2_variable_datastore_info
static struct ao2_containeriax_peercallno_pvts
 Another container of iax2_pvt structures.
static struct ao2_containeriax_transfercallno_pvts
 Another container of iax2_pvt structures.
static int iaxactivethreadcount = 0
static int iaxcompat = 0
static int iaxdebug = 0
static int iaxdefaultdpcache = 10 * 60
static int iaxdefaulttimeout = 5
static int iaxdynamicthreadcount = 0
static int iaxdynamicthreadnum = 0
static int iaxmaxthreadcount = DEFAULT_MAX_THREAD_COUNT
struct ast_custom_function iaxpeer_function
static struct chan_iax2_pvtiaxs [IAX_MAX_CALLS+1]
 an array of iax2 pvt structures
static ast_mutex_t iaxsl [ARRAY_LEN(iaxs)]
 chan_iax2_pvt structure locks
static int iaxthreadcount = DEFAULT_THREAD_COUNT
static int iaxtrunkdebug = 0
static struct ast_custom_function iaxvar_function
static struct idle_list idle_list
static struct io_contextio
static int jittertargetextra = 40
static int lagrq_time = 10
static char language [MAX_LANGUAGE] = ""
static int last_authmethod = 0
static const time_t MAX_CALLTOKEN_DELAY = 10
static int max_reg_expire
static int max_retries = 4
static int maxauthreq = 3
static int maxjitterbuffer = 1000
static int maxjitterinterps = 10
static int maxnontrunkcall = 1
static int maxtrunkcall = TRUNK_CALL_START
static int min_reg_expire
static char mohinterpret [MAX_MUSICCLASS]
static char mohsuggest [MAX_MUSICCLASS]
static struct ast_netsock_listnetsock
static pthread_t netthreadid = AST_PTHREADT_NULL
static struct ast_netsock_listoutsock
static char * papp = "IAX2Provision"
static struct ao2_containerpeercnts
static struct ao2_containerpeers
static int ping_time = 21
static struct ast_codec_pref prefs
struct {
   unsigned int   cos
   unsigned int   tos
qos
static int randomcalltokendata
static char regcontext [AST_MAX_CONTEXT] = ""
static struct registrations registrations
static int resyncthreshold = 1000
static struct ast_sched_threadsched
static int srvlookup = 0
static const char tdesc [] = "Inter Asterisk eXchange Driver (Ver 2)"
static int test_losspct = 0
static struct ast_timertimer
static uint16_t total_nonval_callno_used = 0
static struct tpeers tpeers
static int trunk_maxmtu
static int trunk_nmaxmtu
static int trunk_timed
static int trunk_untimed
static int trunkfreq = 20
static int trunkmaxsize = MAX_TRUNKDATA
static struct ao2_containerusers

Detailed Description

Implementation of Inter-Asterisk eXchange Version 2 as specified in RFC 5456.

Author:
Mark Spencer <markster@digium.com>
See also
Todo:
Implement musicclass settings for IAX2 devices

Definition in file chan_iax2.c.


Define Documentation

#define ACN_FORMAT1   "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"

Referenced by ast_cli_netstats().

#define ACN_FORMAT2   "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"

Referenced by ast_cli_netstats().

#define CALLNO_TO_PTR (   a)    ((void *)(unsigned long)(a))

Definition at line 194 of file chan_iax2.c.

Referenced by ast_iax2_new(), iax2_call(), iax2_hangup(), and update_jbsched().

#define CALLTOKEN_HASH_FORMAT   "%s%d%u%d"

Referenced by handle_call_token().

#define CALLTOKEN_IE_FORMAT   "%u?%s"

Referenced by handle_call_token().

#define DEBUG_SCHED_MULTITHREAD

Definition at line 186 of file chan_iax2.c.

#define DEBUG_SUPPORT

Definition at line 202 of file chan_iax2.c.

#define DEFAULT_CONTEXT   "default"

Definition at line 221 of file chan_iax2.c.

Referenced by check_access(), and handle_cli_iax2_show_users().

#define DEFAULT_DROP   3

Definition at line 200 of file chan_iax2.c.

#define DEFAULT_FREQ_NOTOK   10 * 1000

Definition at line 292 of file chan_iax2.c.

Referenced by build_peer().

#define DEFAULT_FREQ_OK   60 * 1000

Definition at line 291 of file chan_iax2.c.

Referenced by build_peer().

#define DEFAULT_MAX_THREAD_COUNT   100

Definition at line 197 of file chan_iax2.c.

#define DEFAULT_MAXMS   2000

Definition at line 290 of file chan_iax2.c.

Referenced by build_peer(), iax2_poke_peer(), and set_config().

#define DEFAULT_RETRY_TIME   1000

Definition at line 198 of file chan_iax2.c.

Referenced by __find_callno(), and complete_transfer().

#define DEFAULT_THREAD_COUNT   10

Definition at line 196 of file chan_iax2.c.

#define DEFAULT_TRUNKDATA   640 * 10

40ms, uncompressed linear * 10 channels

Definition at line 571 of file chan_iax2.c.

Referenced by iax2_trunk_queue().

#define FORMAT   "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s %-5.10s\n"
#define FORMAT   "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s%s"
#define FORMAT   "%-20.20s %-6.6s %-10.10s %-20.20s %8d %s\n"
#define FORMAT   "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d %-5.5dms %-4.4dms %-4.4dms %-6.6s %s%s %3s%s\n"
#define FORMAT2   "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s %s %9s\n"
#define FORMAT2   "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s %-5.10s\n"
#define FORMAT2   "%-20.20s %-6.6s %-10.10s %-20.20s %8.8s %s\n"
#define FORMAT2   "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s%s"
#define FORMATB   "%-20.20s %-15.15s %-10.10s %5.5d/%5.5d %5.5d/%5.5d [Native Bridged to ID=%5.5d]\n"
#define GAMMA   (0.01)

Definition at line 207 of file chan_iax2.c.

#define IAX2_TRUNK_PREFACE   (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))

Definition at line 492 of file chan_iax2.c.

Referenced by iax2_trunk_queue().

#define IAX_CALLENCRYPTED (   pvt)    (ast_test_flag(pvt, IAX_ENCRYPTED) && ast_test_flag(pvt, IAX_KEYPOPULATED))

Definition at line 295 of file chan_iax2.c.

Referenced by iax2_send(), iax2_start_transfer(), and socket_process().

#define IAX_CAPABILITY_FULLBANDWIDTH   0xFFFF

Definition at line 270 of file chan_iax2.c.

Referenced by cache_get_callno_locked(), and set_config().

#define IAX_CAPABILITY_LOWBANDWIDTH
Value:

Definition at line 281 of file chan_iax2.c.

Referenced by set_config().

#define IAX_CAPABILITY_LOWFREE
Value:

Definition at line 286 of file chan_iax2.c.

#define IAX_CAPABILITY_MEDBANDWIDTH

Definition at line 272 of file chan_iax2.c.

Referenced by set_config().

#define IAX_DEBUGDIGEST (   msg,
  key 
)

Definition at line 298 of file chan_iax2.c.

Referenced by iax2_key_rotate(), and socket_process().

#define MARK_IAX_SUBCLASS_TX   0x8000

Definition at line 579 of file chan_iax2.c.

Referenced by ast_cli_netstats(), handle_cli_iax2_show_channels(), and iax2_send().

#define MAX_JITTER_BUFFER   50

Definition at line 568 of file chan_iax2.c.

#define MAX_PEER_BUCKETS   563

This module will get much higher performance when doing a lot of user and peer lookups if the number of buckets is increased from 1. However, to maintain old behavior for Asterisk 1.4, these are set to 1 by default. When using multiple buckets, search order through these containers is considered random, so you will not be able to depend on the order the entires are specified in iax.conf for matching order.

Definition at line 826 of file chan_iax2.c.

Referenced by load_objects().

#define MAX_RETRY_TIME   10000

Definition at line 566 of file chan_iax2.c.

Referenced by __attempt_transmit(), and iax2_send().

#define MAX_TIMESTAMP_SKEW   160

maximum difference between actual and predicted ts for sending

Definition at line 573 of file chan_iax2.c.

Referenced by calc_timestamp(), and calc_txpeerstamp().

#define MAX_TRUNK_MTU   1240

Maximum transmission unit for the UDP packet in the trunk not to be fragmented. This is based on 1516 - ethernet - ip - udp - iax minus one g711 frame = 1240.

Definition at line 216 of file chan_iax2.c.

Referenced by handle_cli_iax2_set_mtu(), and set_config().

#define MAX_TRUNKDATA   640 * 200

40ms, uncompressed linear * 200 channels

Definition at line 237 of file chan_iax2.c.

Referenced by set_config(), and set_config_destroy().

#define MAX_USER_BUCKETS   MAX_PEER_BUCKETS

Definition at line 830 of file chan_iax2.c.

Referenced by load_objects().

#define MEMORY_SIZE   100

Definition at line 199 of file chan_iax2.c.

#define MIN_JITTER_BUFFER   10

Definition at line 569 of file chan_iax2.c.

#define MIN_RETRY_TIME   100

Definition at line 565 of file chan_iax2.c.

Referenced by iax2_send().

#define MIN_REUSE_TIME   60

Definition at line 204 of file chan_iax2.c.

Referenced by make_trunk(), and sched_delay_remove().

#define SCHED_MULTITHREADED

Definition at line 182 of file chan_iax2.c.

#define schedule_action (   func,
  data 
)    __schedule_action(func, data, __PRETTY_FUNCTION__)
#define TRUNK_CALL_START   IAX_MAX_CALLS / 2
#define TS_GAP_FOR_JB_RESYNC   5000

Definition at line 576 of file chan_iax2.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
CACHE_FLAG_EXISTS 

Extension exists

CACHE_FLAG_NONEXISTENT 

Extension is nonexistent

CACHE_FLAG_CANEXIST 

Extension can exist

CACHE_FLAG_PENDING 

Waiting to hear back response

CACHE_FLAG_TIMEOUT 

Timed out

CACHE_FLAG_TRANSMITTED 

Request transmitted

CACHE_FLAG_UNKNOWN 

Timeout

CACHE_FLAG_MATCHMORE 

Matchmore

Definition at line 886 of file chan_iax2.c.

     {
   /*! Extension exists */
   CACHE_FLAG_EXISTS      = (1 << 0),
   /*! Extension is nonexistent */
   CACHE_FLAG_NONEXISTENT = (1 << 1),
   /*! Extension can exist */
   CACHE_FLAG_CANEXIST    = (1 << 2),
   /*! Waiting to hear back response */
   CACHE_FLAG_PENDING     = (1 << 3),
   /*! Timed out */
   CACHE_FLAG_TIMEOUT     = (1 << 4),
   /*! Request transmitted */
   CACHE_FLAG_TRANSMITTED = (1 << 5),
   /*! Timeout */
   CACHE_FLAG_UNKNOWN     = (1 << 6),
   /*! Matchmore */
   CACHE_FLAG_MATCHMORE   = (1 << 7),
};
anonymous enum
Enumerator:
NEW_PREVENT 
NEW_ALLOW 
NEW_FORCE 
NEW_ALLOW_CALLTOKEN_VALIDATED 

Definition at line 1859 of file chan_iax2.c.

     {
   /* do not allow a new call number, only search ones in use for match */
   NEW_PREVENT = 0,
   /* search for match first, then allow a new one to be allocated */
   NEW_ALLOW = 1,
   /* do not search for match, force a new call number */
   NEW_FORCE = 2,
   /* do not search for match, force a new call number.  Signifies call number
    * has been calltoken validated */
   NEW_ALLOW_CALLTOKEN_VALIDATED = 3,
};

Call token validation settings.

Enumerator:
CALLTOKEN_DEFAULT 

Default calltoken required unless the ip is in the ignorelist.

CALLTOKEN_YES 

Require call token validation.

CALLTOKEN_AUTO 

Require call token validation after a successful registration using call token validation occurs.

CALLTOKEN_NO 

Do not require call token validation.

Definition at line 393 of file chan_iax2.c.

                         {
   /*! \brief Default calltoken required unless the ip is in the ignorelist */
   CALLTOKEN_DEFAULT = 0,
   /*! \brief Require call token validation. */
   CALLTOKEN_YES = 1,
   /*! \brief Require call token validation after a successful registration
    *         using call token validation occurs. */
   CALLTOKEN_AUTO = 2,
   /*! \brief Do not require call token validation. */
   CALLTOKEN_NO = 3,
};
enum iax2_flags
Enumerator:
IAX_HASCALLERID 

CallerID has been specified

IAX_DELME 

Needs to be deleted

IAX_TEMPONLY 

Temporary (realtime)

IAX_TRUNK 

Treat as a trunk

IAX_NOTRANSFER 

Don't native bridge

IAX_USEJITTERBUF 

Use jitter buffer

IAX_DYNAMIC 

dynamic peer

IAX_SENDANI 

Send ANI along with CallerID

IAX_ALREADYGONE 

Already disconnected

IAX_PROVISION 

This is a provisioning request

IAX_QUELCH 

Whether or not we quelch audio

IAX_ENCRYPTED 

Whether we should assume encrypted tx/rx

IAX_KEYPOPULATED 

Whether we have a key populated

IAX_CODEC_USER_FIRST 

are we willing to let the other guy choose the codec?

IAX_CODEC_NOPREFS 

Force old behaviour by turning off prefs

IAX_CODEC_NOCAP 

only consider requested format and ignore capabilities

IAX_RTCACHEFRIENDS 

let realtime stay till your reload

IAX_RTUPDATE 

Send a realtime update

IAX_RTAUTOCLEAR 

erase me on expire

IAX_FORCEJITTERBUF 

Force jitterbuffer, even when bridged to a channel that can take jitter

IAX_RTIGNOREREGEXPIRE 

When using realtime, ignore registration expiration

IAX_TRUNKTIMESTAMPS 

Send trunk timestamps

IAX_TRANSFERMEDIA 

When doing IAX2 transfers, transfer media only

IAX_MAXAUTHREQ 

Maximum outstanding AUTHREQ restriction is in place

IAX_DELAYPBXSTART 

Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else

IAX_ALLOWFWDOWNLOAD 

Allow the FWDOWNL command?

IAX_IMMEDIATE 

Allow immediate off-hook to extension s

IAX_FORCE_ENCRYPT 

Forces call encryption, if encryption not possible hangup

IAX_SHRINKCALLERID 

Turn on and off caller id shrinking

Definition at line 351 of file chan_iax2.c.

                {
   IAX_HASCALLERID =    (1 << 0),   /*!< CallerID has been specified */
   IAX_DELME =    (1 << 1),   /*!< Needs to be deleted */
   IAX_TEMPONLY =    (1 << 2),   /*!< Temporary (realtime) */
   IAX_TRUNK =    (1 << 3),   /*!< Treat as a trunk */
   IAX_NOTRANSFER =  (1 << 4),   /*!< Don't native bridge */
   IAX_USEJITTERBUF =   (1 << 5),   /*!< Use jitter buffer */
   IAX_DYNAMIC =     (1 << 6),   /*!< dynamic peer */
   IAX_SENDANI =     (1 << 7),   /*!< Send ANI along with CallerID */
        /* (1 << 8) is currently unused due to the deprecation of an old option. Go ahead, take it! */
   IAX_ALREADYGONE = (1 << 9),   /*!< Already disconnected */
   IAX_PROVISION =      (1 << 10),  /*!< This is a provisioning request */
   IAX_QUELCH =      (1 << 11),  /*!< Whether or not we quelch audio */
   IAX_ENCRYPTED =      (1 << 12),  /*!< Whether we should assume encrypted tx/rx */
   IAX_KEYPOPULATED =   (1 << 13),  /*!< Whether we have a key populated */
   IAX_CODEC_USER_FIRST =  (1 << 14),  /*!< are we willing to let the other guy choose the codec? */
   IAX_CODEC_NOPREFS =     (1 << 15),  /*!< Force old behaviour by turning off prefs */
   IAX_CODEC_NOCAP =    (1 << 16),  /*!< only consider requested format and ignore capabilities*/
   IAX_RTCACHEFRIENDS =    (1 << 17),  /*!< let realtime stay till your reload */
   IAX_RTUPDATE =       (1 << 18),  /*!< Send a realtime update */
   IAX_RTAUTOCLEAR =    (1 << 19),  /*!< erase me on expire */ 
   IAX_FORCEJITTERBUF = (1 << 20),  /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */ 
   IAX_RTIGNOREREGEXPIRE = (1 << 21),  /*!< When using realtime, ignore registration expiration */
   IAX_TRUNKTIMESTAMPS =   (1 << 22),  /*!< Send trunk timestamps */
   IAX_TRANSFERMEDIA =     (1 << 23),      /*!< When doing IAX2 transfers, transfer media only */
   IAX_MAXAUTHREQ =        (1 << 24),      /*!< Maximum outstanding AUTHREQ restriction is in place */
   IAX_DELAYPBXSTART =  (1 << 25),  /*!< Don't start a PBX on the channel until the peer sends us a
                       response, so that we've achieved a three-way handshake with
                       them before sending voice or anything else*/
   IAX_ALLOWFWDOWNLOAD =   (1 << 26),  /*!< Allow the FWDOWNL command? */
   IAX_IMMEDIATE =      (1 << 27),      /*!< Allow immediate off-hook to extension s */
   IAX_FORCE_ENCRYPT =  (1 << 28),      /*!< Forces call encryption, if encryption not possible hangup */
   IAX_SHRINKCALLERID = (1 << 29),   /*!< Turn on and off caller id shrinking */
};
enum iax2_state
Enumerator:
IAX_STATE_STARTED 
IAX_STATE_AUTHENTICATED 
IAX_STATE_TBD 

Definition at line 340 of file chan_iax2.c.

                {
   IAX_STATE_STARTED =        (1 << 0),
   IAX_STATE_AUTHENTICATED =  (1 << 1),
   IAX_STATE_TBD =            (1 << 2),
};
Enumerator:
IAX_IOSTATE_IDLE 
IAX_IOSTATE_READY 
IAX_IOSTATE_PROCESSING 
IAX_IOSTATE_SCHEDREADY 

Definition at line 927 of file chan_iax2.c.

Enumerator:
IAX_THREAD_TYPE_POOL 
IAX_THREAD_TYPE_DYNAMIC 

Definition at line 934 of file chan_iax2.c.

Enumerator:
REG_STATE_UNREGISTERED 
REG_STATE_REGSENT 
REG_STATE_AUTHSENT 
REG_STATE_REGISTERED 
REG_STATE_REJECTED 
REG_STATE_TIMEOUT 
REG_STATE_NOAUTH 

Definition at line 524 of file chan_iax2.c.

Enumerator:
TRANSFER_NONE 
TRANSFER_BEGIN 
TRANSFER_READY 
TRANSFER_RELEASED 
TRANSFER_PASSTHROUGH 
TRANSFER_MBEGIN 
TRANSFER_MREADY 
TRANSFER_MRELEASED 
TRANSFER_MPASSTHROUGH 
TRANSFER_MEDIA 
TRANSFER_MEDIAPASS 

Definition at line 534 of file chan_iax2.c.


Function Documentation

static void __attempt_transmit ( const void *  data) [static]

Definition at line 3329 of file chan_iax2.c.

References chan_iax2_pvt::addr, iax_frame::af, AST_CAUSE_DESTINATION_OUT_OF_ORDER, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, AST_FRAME_IAX, ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), attempt_transmit(), iax_frame::callno, chan_iax2_pvt::error, f, iax_frame::final, ast_frame::frametype, ast_channel::hangupcause, iax2_destroy(), iax2_frame_free(), iax2_queue_frame(), iax2_sched_add(), IAX_COMMAND_TXREJ, IAX_DEFAULT_REG_EXPIRE, LOG_WARNING, MAX_RETRY_TIME, ast_channel::name, iax_frame::oseqno, chan_iax2_pvt::owner, iax2_registry::refresh, chan_iax2_pvt::reg, REG_STATE_TIMEOUT, iax2_registry::regstate, iax_frame::retrans, iax_frame::retries, iax_frame::retrytime, send_command(), send_packet(), ast_frame::subclass, iax_frame::transfer, iax_frame::ts, update_packet(), and iax2_registry::us.

Referenced by attempt_transmit().

{
   /* Attempt to transmit the frame to the remote peer...
      Called without iaxsl held. */
   struct iax_frame *f = (struct iax_frame *)data;
   int freeme = 0;
   int callno = f->callno;
   /* Make sure this call is still active */
   if (callno) 
      ast_mutex_lock(&iaxsl[callno]);
   if (callno && iaxs[callno]) {
      if ((f->retries < 0) /* Already ACK'd */ ||
          (f->retries >= max_retries) /* Too many attempts */) {
            /* Record an error if we've transmitted too many times */
            if (f->retries >= max_retries) {
               if (f->transfer) {
                  /* Transfer timeout */
                  send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
               } else if (f->final) {
                  iax2_destroy(callno);
               } else {
                  if (iaxs[callno]->owner)
                     ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno);
                  iaxs[callno]->error = ETIMEDOUT;
                  if (iaxs[callno]->owner) {
                     struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
                     /* Hangup the fd */
                     iax2_queue_frame(callno, &fr); /* XXX */
                     /* Remember, owner could disappear */
                     if (iaxs[callno] && iaxs[callno]->owner)
                        iaxs[callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
                  } else {
                     if (iaxs[callno]->reg) {
                        memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
                        iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
                        iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
                     }
                     iax2_destroy(callno);
                  }
               }

            }
            freeme = 1;
      } else {
         /* Update it if it needs it */
         update_packet(f);
         /* Attempt transmission */
         send_packet(f);
         f->retries++;
         /* Try again later after 10 times as long */
         f->retrytime *= 10;
         if (f->retrytime > MAX_RETRY_TIME)
            f->retrytime = MAX_RETRY_TIME;
         /* Transfer messages max out at one second */
         if (f->transfer && (f->retrytime > 1000))
            f->retrytime = 1000;
         f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);
      }
   } else {
      /* Make sure it gets freed */
      f->retries = -1;
      freeme = 1;
   }
   if (callno)
      ast_mutex_unlock(&iaxsl[callno]);
   /* Do not try again */
   if (freeme) {
      /* Don't attempt delivery, just remove it from the queue */
      AST_LIST_LOCK(&frame_queue);
      AST_LIST_REMOVE(&frame_queue, f, list);
      AST_LIST_UNLOCK(&frame_queue);
      f->retrans = -1; /* this is safe because this is the scheduled function */
      /* Free the IAX frame */
      iax2_frame_free(f);
   }
}
static void __auth_reject ( const void *  nothing) [static]

Definition at line 8640 of file chan_iax2.c.

References AST_CAUSE_FACILITY_NOT_SUBSCRIBED, AST_CAUSE_FACILITY_REJECTED, AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), iax_ie_data::buf, IAX_COMMAND_REGREJ, IAX_COMMAND_REJECT, iax_ie_append_byte(), iax_ie_append_str(), IAX_IE_CAUSE, IAX_IE_CAUSECODE, iax_ie_data::pos, and send_command_final().

Referenced by auth_reject().

{
   /* Called from IAX thread only, without iaxs lock */
   int callno = (int)(long)(nothing);
   struct iax_ie_data ied;
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      memset(&ied, 0, sizeof(ied));
      if (iaxs[callno]->authfail == IAX_COMMAND_REGREJ) {
         iax_ie_append_str(&ied, IAX_IE_CAUSE, "Registration Refused");
         iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_REJECTED);
      } else if (iaxs[callno]->authfail == IAX_COMMAND_REJECT) {
         iax_ie_append_str(&ied, IAX_IE_CAUSE, "No authority found");
         iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
      }
      send_command_final(iaxs[callno], AST_FRAME_IAX, iaxs[callno]->authfail, 0, ied.buf, ied.pos, -1);
   }
   ast_mutex_unlock(&iaxsl[callno]);
}
static void __auto_congest ( const void *  nothing) [static]

Definition at line 4459 of file chan_iax2.c.

References AST_CONTROL_CONGESTION, AST_FRAME_CONTROL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), iax2_queue_frame(), chan_iax2_pvt::initid, LOG_NOTICE, and PTR_TO_CALLNO.

Referenced by auto_congest().

{
   int callno = PTR_TO_CALLNO(nothing);
   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_CONGESTION };
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      iaxs[callno]->initid = -1;
      iax2_queue_frame(callno, &f);
      ast_log(LOG_NOTICE, "Auto-congesting call due to slow response\n");
   }
   ast_mutex_unlock(&iaxsl[callno]);
}
static void __auto_hangup ( const void *  nothing) [static]

Definition at line 8689 of file chan_iax2.c.

References AST_CAUSE_NO_USER_RESPONSE, AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), iax_ie_data::buf, IAX_COMMAND_HANGUP, iax_ie_append_byte(), iax_ie_append_str(), IAX_IE_CAUSE, IAX_IE_CAUSECODE, iax_ie_data::pos, and send_command_final().

Referenced by auto_hangup().

{
   /* Called from IAX thread only, without iaxs lock */
   int callno = (int)(long)(nothing);
   struct iax_ie_data ied;
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      memset(&ied, 0, sizeof(ied));
      iax_ie_append_str(&ied, IAX_IE_CAUSE, "Timeout");
      iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_NO_USER_RESPONSE);
      send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1);
   }
   ast_mutex_unlock(&iaxsl[callno]);
}
static int __do_deliver ( void *  data) [static]
Note:
This function assumes that iaxsl[callno] is locked when called.
IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] was valid before calling it, it may no longer be valid after calling it. This function calls iax2_queue_frame(), which may unlock and lock the mutex associated with this callno, meaning that another thread may grab it and destroy the call.

Definition at line 3115 of file chan_iax2.c.

References iax_frame::af, ast_clear_flag, AST_FRFLAG_HAS_TIMING_INFO, ast_test_flag, iax_frame::callno, iax_frame::data, iax2_frame_free(), iax2_queue_frame(), IAX_ALREADYGONE, and iax_frame::retrans.

Referenced by __get_from_jb(), and schedule_delivery().

{
   /* Just deliver the packet by using queueing.  This is called by
     the IAX thread with the iaxsl lock held. */
   struct iax_frame *fr = data;
   fr->retrans = -1;
   ast_clear_flag(&fr->af, AST_FRFLAG_HAS_TIMING_INFO);
   if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))
      iax2_queue_frame(fr->callno, &fr->af);
   /* Free our iax frame */
   iax2_frame_free(fr);
   /* And don't run again */
   return 0;
}
static void __expire_registry ( const void *  data) [static]

Definition at line 8288 of file chan_iax2.c.

References iax2_peer::addr, ast_db_del(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_test_flag, EVENT_FLAG_SYSTEM, iax2_peer::expire, iax2_peer::expiry, iax2_regfunk, IAX_RTAUTOCLEAR, IAX_RTCACHEFRIENDS, IAX_RTUPDATE, IAX_TEMPONLY, manager_event, min_reg_expire, iax2_peer::name, peer_unref(), peercnt_modify(), realtime_update_peer(), register_peer_exten(), and unlink_peer().

Referenced by expire_registry().

{
   struct iax2_peer *peer = (struct iax2_peer *) data;

   if (!peer)
      return;

   peer->expire = -1;

   ast_debug(1, "Expiring registration for peer '%s'\n", peer->name);
   if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
      realtime_update_peer(peer->name, &peer->addr, 0);
   manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
   /* modify entry in peercnts table as _not_ registered */
   peercnt_modify(0, 0, &peer->addr);
   /* Reset the address */
   memset(&peer->addr, 0, sizeof(peer->addr));
   /* Reset expiry value */
   peer->expiry = min_reg_expire;
   if (!ast_test_flag(peer, IAX_TEMPONLY))
      ast_db_del("IAX/Registry", peer->name);
   register_peer_exten(peer, 0);
   ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
   if (iax2_regfunk)
      iax2_regfunk(peer->name, 0);

   if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
      unlink_peer(peer);

   peer_unref(peer);
}
static int __find_callno ( unsigned short  callno,
unsigned short  dcallno,
struct sockaddr_in *  sin,
int  new,
int  sockfd,
int  return_locked,
int  check_dcallno 
) [static]

Definition at line 2617 of file chan_iax2.c.

References chan_iax2_pvt::addr, amaflags, chan_iax2_pvt::amaflags, ao2_find, ao2_ref, ast_copy_flags, ast_debug, ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_string_field_set, callno_entry::callno, chan_iax2_pvt::callno, chan_iax2_pvt::callno_entry, DEFAULT_RETRY_TIME, chan_iax2_pvt::expiry, get_unused_callno(), iax2_getpeername(), iax2_sched_add(), IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_NOTRANSFER, IAX_TRANSFERMEDIA, IAX_USEJITTERBUF, chan_iax2_pvt::lagid, LOG_WARNING, match(), maxnontrunkcall, maxtrunkcall, min_reg_expire, NEW_ALLOW, new_iax(), OBJ_POINTER, parkinglot, chan_iax2_pvt::peercallno, peercnt_add(), peercnt_remove_by_addr(), chan_iax2_pvt::pingid, chan_iax2_pvt::pingtime, replace_callno(), send_lagrq(), send_ping(), iax2_trunk_peer::sockfd, chan_iax2_pvt::sockfd, store_by_peercallno(), chan_iax2_pvt::transfer, TRUNK_CALL_START, and update_max_nontrunk().

Referenced by find_callno(), and find_callno_locked().

{
   int res = 0;
   int x;
   /* this call is calltoken validated as long as it is either NEW_FORCE
    * or NEW_ALLOW_CALLTOKEN_VALIDATED */
   int validated = (new > NEW_ALLOW) ? 1 : 0;
   char host[80];

   if (new <= NEW_ALLOW) {
      if (callno) {
         struct chan_iax2_pvt *pvt;
         struct chan_iax2_pvt tmp_pvt = {
            .callno = dcallno,
            .peercallno = callno,
            .transfercallno = callno,
            /* hack!! */
            .frames_received = check_dcallno,
         };

         memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
         /* this works for finding normal call numbers not involving transfering */ 
         if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
            if (return_locked) {
               ast_mutex_lock(&iaxsl[pvt->callno]);
            }
            res = pvt->callno;
            ao2_ref(pvt, -1);
            pvt = NULL;
            return res;
         }
         /* this searches for transfer call numbers that might not get caught otherwise */
         memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
         memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.transfer));
         if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
            if (return_locked) {
               ast_mutex_lock(&iaxsl[pvt->callno]);
            }
            res = pvt->callno;
            ao2_ref(pvt, -1);
            pvt = NULL;
            return res;
         }
      }
         /* This will occur on the first response to a message that we initiated,
       * such as a PING. */
      if (dcallno) {
         ast_mutex_lock(&iaxsl[dcallno]);
      }
      if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {
         iaxs[dcallno]->peercallno = callno;
         res = dcallno;
         store_by_peercallno(iaxs[dcallno]);
         if (!res || !return_locked) {
            ast_mutex_unlock(&iaxsl[dcallno]);
         }
         return res;
      }
      if (dcallno) {
         ast_mutex_unlock(&iaxsl[dcallno]);
      }
#ifdef IAX_OLD_FIND
      /* If we get here, we SHOULD NOT find a call structure for this
         callno; if we do, it means that there is a call structure that
         has a peer callno but did NOT get entered into the hash table,
         which is bad.

         If we find a call structure using this old, slow method, output a log
         message so we'll know about it. After a few months of leaving this in
         place, if we don't hear about people seeing these messages, we can
         remove this code for good.
      */

      for (x = 1; !res && x < maxnontrunkcall; x++) {
         ast_mutex_lock(&iaxsl[x]);
         if (iaxs[x]) {
            /* Look for an exact match */
            if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
               res = x;
            }
         }
         if (!res || !return_locked)
            ast_mutex_unlock(&iaxsl[x]);
      }
      for (x = TRUNK_CALL_START; !res && x < maxtrunkcall; x++) {
         ast_mutex_lock(&iaxsl[x]);
         if (iaxs[x]) {
            /* Look for an exact match */
            if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
               res = x;
            }
         }
         if (!res || !return_locked)
            ast_mutex_unlock(&iaxsl[x]);
      }
#endif
   }
   if (!res && (new >= NEW_ALLOW)) {
      struct callno_entry *callno_entry;
      /* It may seem odd that we look through the peer list for a name for
       * this *incoming* call.  Well, it is weird.  However, users don't
       * have an IP address/port number that we can match against.  So,
       * this is just checking for a peer that has that IP/port and
       * assuming that we have a user of the same name.  This isn't always
       * correct, but it will be changed if needed after authentication. */
      if (!iax2_getpeername(*sin, host, sizeof(host)))
         snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));

      if (peercnt_add(sin)) {
         /* This address has hit its callnumber limit.  When the limit
          * is reached, the connection is not added to the peercnts table.*/
         return 0;
      }

      if (!(callno_entry = get_unused_callno(0, validated))) {
         /* since we ran out of space, remove the peercnt
          * entry we added earlier */
         peercnt_remove_by_addr(sin);
         ast_log(LOG_WARNING, "No more space\n");
         return 0;
      }
      x = callno_entry->callno;
      ast_mutex_lock(&iaxsl[x]);

      iaxs[x] = new_iax(sin, host);
      update_max_nontrunk();
      if (iaxs[x]) {
         if (iaxdebug)
            ast_debug(1, "Creating new call structure %d\n", x);
         iaxs[x]->callno_entry = callno_entry;
         iaxs[x]->sockfd = sockfd;
         iaxs[x]->addr.sin_port = sin->sin_port;
         iaxs[x]->addr.sin_family = sin->sin_family;
         iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
         iaxs[x]->peercallno = callno;
         iaxs[x]->callno = x;
         iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
         iaxs[x]->expiry = min_reg_expire;
         iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
         iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
         iaxs[x]->amaflags = amaflags;
         ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT); 
         ast_string_field_set(iaxs[x], accountcode, accountcode);
         ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
         ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
         ast_string_field_set(iaxs[x], parkinglot, default_parkinglot);

         if (iaxs[x]->peercallno) {
            store_by_peercallno(iaxs[x]);
         }
      } else {
         ast_log(LOG_WARNING, "Out of resources\n");
         ast_mutex_unlock(&iaxsl[x]);
         replace_callno(callno_entry);
         return 0;
      }
      if (!return_locked)
         ast_mutex_unlock(&iaxsl[x]);
      res = x;
   }
   return res;
}
static void __get_from_jb ( const void *  p) [static]

Definition at line 3901 of file chan_iax2.c.

References __do_deliver(), ast_codec_interp_len(), ast_format_rate(), AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_test_flag, ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), jb_frame::data, ast_frame::delivery, ast_frame::frametype, iax2_frame_free(), iax2_queue_frame(), IAX_ALREADYGONE, chan_iax2_pvt::jb, JB_DROP, JB_EMPTY, jb_get(), JB_INTERP, jb_next(), JB_NOFRAME, JB_OK, chan_iax2_pvt::jbid, jb_frame::ms, iax2_trunk_peer::next, ast_frame::offset, PTR_TO_CALLNO, chan_iax2_pvt::rxcore, ast_frame::samples, ast_frame::src, ast_frame::subclass, update_jbsched(), and chan_iax2_pvt::voiceformat.

Referenced by get_from_jb().

{
   int callno = PTR_TO_CALLNO(p);
   struct chan_iax2_pvt *pvt = NULL;
   struct iax_frame *fr;
   jb_frame frame;
   int ret;
   long ms;
   long next;
   struct timeval now = ast_tvnow();
   
   /* Make sure we have a valid private structure before going on */
   ast_mutex_lock(&iaxsl[callno]);
   pvt = iaxs[callno];
   if (!pvt) {
      /* No go! */
      ast_mutex_unlock(&iaxsl[callno]);
      return;
   }

   pvt->jbid = -1;
   
   /* round up a millisecond since ast_sched_runq does; */
   /* prevents us from spinning while waiting for our now */
   /* to catch up with runq's now */
   now.tv_usec += 1000;
   
   ms = ast_tvdiff_ms(now, pvt->rxcore);
   
   if(ms >= (next = jb_next(pvt->jb))) {
      ret = jb_get(pvt->jb,&frame,ms,ast_codec_interp_len(pvt->voiceformat));
      switch(ret) {
      case JB_OK:
         fr = frame.data;
         __do_deliver(fr);
         /* __do_deliver() can cause the call to disappear */
         pvt = iaxs[callno];
         break;
      case JB_INTERP:
      {
         struct ast_frame af = { 0, };
         
         /* create an interpolation frame */
         af.frametype = AST_FRAME_VOICE;
         af.subclass = pvt->voiceformat;
         af.samples  = frame.ms * (ast_format_rate(pvt->voiceformat) / 1000);
         af.src  = "IAX2 JB interpolation";
         af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
         af.offset = AST_FRIENDLY_OFFSET;
         
         /* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
          * which we'd need to malloc, and then it would free it.  That seems like a drag */
         if (!ast_test_flag(iaxs[callno], IAX_ALREADYGONE)) {
            iax2_queue_frame(callno, &af);
            /* iax2_queue_frame() could cause the call to disappear */
            pvt = iaxs[callno];
         }
      }
         break;
      case JB_DROP:
         iax2_frame_free(frame.data);
         break;
      case JB_NOFRAME:
      case JB_EMPTY:
         /* do nothing */
         break;
      default:
         /* shouldn't happen */
         break;
      }
   }
   if (pvt)
      update_jbsched(pvt);
   ast_mutex_unlock(&iaxsl[callno]);
}
static void __iax2_do_register_s ( const void *  data) [static]

Definition at line 7962 of file chan_iax2.c.

References iax2_registry::expire, and iax2_do_register().

Referenced by iax2_do_register_s().

{
   struct iax2_registry *reg = (struct iax2_registry *)data;
   reg->expire = -1;
   iax2_do_register(reg);
}
static void __iax2_poke_noanswer ( const void *  data) [static]

Definition at line 11487 of file chan_iax2.c.

References AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), iax2_peer::callno, EVENT_FLAG_SYSTEM, iax2_destroy(), iax2_poke_peer_s(), iax2_sched_add(), iax2_peer::lastms, LOG_NOTICE, manager_event, iax2_peer::name, peer_ref(), peer_unref(), iax2_peer::pokeexpire, and iax2_peer::pokefreqnotok.

Referenced by iax2_poke_noanswer().

{
   struct iax2_peer *peer = (struct iax2_peer *)data;
   int callno;

   if (peer->lastms > -1) {
      ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
      manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
      ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
   }
   if ((callno = peer->callno) > 0) {
      ast_mutex_lock(&iaxsl[callno]);
      iax2_destroy(callno);
      ast_mutex_unlock(&iaxsl[callno]);
   }
   peer->callno = 0;
   peer->lastms = -1;
   /* Try again quickly */
   peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
   if (peer->pokeexpire == -1)
      peer_unref(peer);
}
static void __iax2_poke_peer_s ( const void *  data) [static]

Definition at line 8752 of file chan_iax2.c.

References iax2_poke_peer(), and peer_unref().

Referenced by iax2_poke_peer_s().

{
   struct iax2_peer *peer = (struct iax2_peer *)data;
   iax2_poke_peer(peer, 0);
   peer_unref(peer);
}
static int __iax2_show_peers ( int  manager,
int  fd,
struct mansession s,
int  argc,
char *  argv[] 
) [static]

Definition at line 6357 of file chan_iax2.c.

References iax2_peer::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli(), ast_copy_string(), ast_inet_ntoa(), ast_str_alloca, ast_str_buffer(), ast_strlen_zero(), ast_test_flag, astman_append(), iax2_peer::encmethods, encmethods_to_str(), FORMAT, FORMAT2, IAX_DYNAMIC, IAX_TRUNK, iax2_peer::mask, iax2_peer::name, name, peer_status(), peer_unref(), RESULT_SHOWUSAGE, RESULT_SUCCESS, status, and iax2_peer::username.

Referenced by handle_cli_iax2_show_peers(), and manager_iax2_show_peers().

{
   regex_t regexbuf;
   int havepattern = 0;
   int total_peers = 0;
   int online_peers = 0;
   int offline_peers = 0;
   int unmonitored_peers = 0;
   struct ao2_iterator i;

#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-10s%s"
#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-10s%s"

   struct iax2_peer *peer = NULL;
   char name[256];
   struct ast_str *encmethods = ast_str_alloca(256);
   int registeredonly=0;
   char *term = manager ? "\r\n" : "\n";
   char idtext[256] = "";
   switch (argc) {
   case 6:
      if (!strcasecmp(argv[3], "registered"))
         registeredonly = 1;
      else
         return RESULT_SHOWUSAGE;
      if (!strcasecmp(argv[4], "like")) {
         if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
            return RESULT_SHOWUSAGE;
         havepattern = 1;
      } else
         return RESULT_SHOWUSAGE;
      break;
   case 5:
      if (!strcasecmp(argv[3], "like")) {
         if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
            return RESULT_SHOWUSAGE;
         havepattern = 1;
      } else
         return RESULT_SHOWUSAGE;
      break;
   case 4:
      if (!strcasecmp(argv[3], "registered"))
         registeredonly = 1;
      else
         return RESULT_SHOWUSAGE;
      break;
   case 3:
      break;
   default:
      return RESULT_SHOWUSAGE;
   }


   if (!s)
      ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);

   i = ao2_iterator_init(peers, 0);
   for (peer = ao2_iterator_next(&i); peer; 
      peer_unref(peer), peer = ao2_iterator_next(&i)) {
      char nm[20];
      char status[20];
      int retstatus;

      if (registeredonly && !peer->addr.sin_addr.s_addr)
         continue;
      if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0))
         continue;

      if (!ast_strlen_zero(peer->username))
         snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
      else
         ast_copy_string(name, peer->name, sizeof(name));

      encmethods_to_str(peer->encmethods, encmethods);
      retstatus = peer_status(peer, status, sizeof(status));
      if (retstatus > 0)
         online_peers++;
      else if (!retstatus)
         offline_peers++;
      else
         unmonitored_peers++;

      ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));

      if (s) {
         astman_append(s,
            "Event: PeerEntry\r\n%s"
            "Channeltype: IAX2\r\n"
            "ChanObjectType: peer\r\n"
            "ObjectName: %s\r\n"
            "IPaddress: %s\r\n"
            "IPport: %d\r\n"
            "Dynamic: %s\r\n"
            "Trunk: %s\r\n"
            "Encryption: %s\r\n"
            "Status: %s\r\n\r\n",
            idtext,
            name,
            peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "-none-",
            ntohs(peer->addr.sin_port),
            ast_test_flag(peer, IAX_DYNAMIC) ? "yes" : "no",
            ast_test_flag(peer, IAX_TRUNK) ? "yes" : "no",
            peer->encmethods ? ast_str_buffer(encmethods) : "no",
            status);
      } else {
         ast_cli(fd, FORMAT, name,
            peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
            ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
            nm,
            ntohs(peer->addr.sin_port),
            ast_test_flag(peer, IAX_TRUNK) ? "(T)" : "   ",
            peer->encmethods ? "(E)" : "   ",
            status,
            term);
      }
      total_peers++;
   }
   ao2_iterator_destroy(&i);

   if (!s)
      ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);

   if (havepattern)
      regfree(&regexbuf);

   return RESULT_SUCCESS;
#undef FORMAT
#undef FORMAT2
}
static void __reg_module ( void  ) [static]

Definition at line 13972 of file chan_iax2.c.

static int __schedule_action ( void(*)(const void *data)  func,
const void *  data,
const char *  funcname 
) [static]

Definition at line 1365 of file chan_iax2.c.

References ast_copy_string(), ast_debug, iax2_thread::cond, iax2_thread::curfunc, find_idle_thread(), IAX_IOSTATE_SCHEDREADY, iax2_thread::iostate, iax2_thread::lock, iax2_thread::scheddata, iax2_thread::schedfunc, signal_condition(), and thread.

{
   struct iax2_thread *thread = NULL;
   static time_t lasterror;
   static time_t t;

   thread = find_idle_thread();

   if (thread != NULL) {
      thread->schedfunc = func;
      thread->scheddata = data;
      thread->iostate = IAX_IOSTATE_SCHEDREADY;
#ifdef DEBUG_SCHED_MULTITHREAD
      ast_copy_string(thread->curfunc, funcname, sizeof(thread->curfunc));
#endif
      signal_condition(&thread->lock, &thread->cond);
      return 0;
   }
   time(&t);
   if (t != lasterror) 
      ast_debug(1, "Out of idle IAX2 threads for scheduling!\n");
   lasterror = t;

   return -1;
}
static int __send_command ( struct chan_iax2_pvt i,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen,
int  seqno,
int  now,
int  transfer,
int  final 
) [static]

Definition at line 7162 of file chan_iax2.c.

References ast_frame::data, ast_frame::datalen, ast_frame::frametype, iax2_send(), ast_frame::ptr, queue_signalling(), ast_frame::src, ast_frame::subclass, and type.

Referenced by send_command(), send_command_final(), send_command_immediate(), and send_command_transfer().

{
   struct ast_frame f = { 0, };
   int res = 0;

   f.frametype = type;
   f.subclass = command;
   f.datalen = datalen;
   f.src = __FUNCTION__;
   f.data.ptr = (void *) data;

   if ((res = queue_signalling(i, &f)) <= 0) {
      return res;
   }

   return iax2_send(i, &f, ts, seqno, now, transfer, final);
}
static void __send_lagrq ( const void *  data) [static]

Definition at line 1470 of file chan_iax2.c.

References ast_debug, AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), iax2_thread::callno, iax2_sched_add(), IAX_COMMAND_LAGRQ, chan_iax2_pvt::lagid, send_command(), and send_lagrq().

Referenced by send_lagrq().

{
   int callno = (long) data;

   ast_mutex_lock(&iaxsl[callno]);

   if (iaxs[callno]) {
      if (iaxs[callno]->peercallno) {
         send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
         iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
      } else {
         /* I am the schedule, so I'm allowed to do this */
         iaxs[callno]->lagid = -1;
      }
   } else {
      ast_debug(1, "I was supposed to send a LAGRQ with callno %d, but no such call exists.\n", callno);
   }

   ast_mutex_unlock(&iaxsl[callno]);
}
static void __send_ping ( const void *  data) [static]

Definition at line 1409 of file chan_iax2.c.

References ast_debug, AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), iax2_thread::callno, iax2_sched_add(), IAX_COMMAND_PING, chan_iax2_pvt::pingid, send_command(), and send_ping().

Referenced by send_ping().

{
   int callno = (long) data;

   ast_mutex_lock(&iaxsl[callno]);

   if (iaxs[callno]) {
      if (iaxs[callno]->peercallno) {
         send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
         iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
      } else {
         /* I am the schedule, so I'm allowed to do this */
         iaxs[callno]->pingid = -1;
      }
   } else {
      ast_debug(1, "I was supposed to send a PING with callno %d, but no such call exists.\n", callno);
   }

   ast_mutex_unlock(&iaxsl[callno]);
}
static int __unload_module ( void  ) [static]

Definition at line 13684 of file chan_iax2.c.

References ao2_ref, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_manager_unregister(), ast_mutex_destroy(), ast_netsock_release(), AST_PTHREADT_NULL, ast_sched_thread_destroy(), ast_timer_close(), ast_unload_realtime(), ast_unregister_application(), ast_unregister_switch(), cleanup_thread_list(), delete_users(), iax2_destroy(), iax_provision_unload(), and reload_firmware().

Referenced by load_module(), and unload_module().

static void __unreg_module ( void  ) [static]

Definition at line 13972 of file chan_iax2.c.

static int acf_channel_read ( struct ast_channel chan,
const char *  funcname,
char *  preparse,
char *  buf,
size_t  buflen 
) [static]

Definition at line 13449 of file chan_iax2.c.

References chan_iax2_pvt::addr, ast_copy_string(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), chan_iax2_pvt::callno, LOG_ERROR, chan_iax2_pvt::osptoken, PTR_TO_CALLNO, ast_channel::tech, ast_channel::tech_pvt, and chan_iax2_pvt::username.

{
   struct chan_iax2_pvt *pvt;
   unsigned int callno;
   int res = 0;

   if (!chan || chan->tech != &iax2_tech) {
      ast_log(LOG_ERROR, "This function requires a valid IAX2 channel\n");
      return -1;
   }

   callno = PTR_TO_CALLNO(chan->tech_pvt);
   ast_mutex_lock(&iaxsl[callno]);
   if (!(pvt = iaxs[callno])) {
      ast_mutex_unlock(&iaxsl[callno]);
      return -1;
   }

   if (!strcasecmp(args, "osptoken")) {
      ast_copy_string(buf, pvt->osptoken, buflen);
   } else if (!strcasecmp(args, "peerip")) {
      ast_copy_string(buf, pvt->addr.sin_addr.s_addr ? ast_inet_ntoa(pvt->addr.sin_addr) : "", buflen);
   } else if (!strcasecmp(args, "peername")) {
      ast_copy_string(buf, pvt->username, buflen);
   } else {
      res = -1;
   }

   ast_mutex_unlock(&iaxsl[callno]);

   return res;
}
static int acf_iaxvar_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 9421 of file chan_iax2.c.

References ast_channel_datastore_find(), ast_copy_string(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_datastore::data, ast_var_t::entries, ast_var_t::name, ast_var_t::value, and var.

{
   struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
   AST_LIST_HEAD(, ast_var_t) *varlist;
   struct ast_var_t *var;

   if (!variablestore) {
      *buf = '\0';
      return 0;
   }
   varlist = variablestore->data;

   AST_LIST_LOCK(varlist);
   AST_LIST_TRAVERSE(varlist, var, entries) {
      if (strcmp(var->name, data) == 0) {
         ast_copy_string(buf, var->value, len);
         break;
      }
   }
   AST_LIST_UNLOCK(varlist);
   return 0;
}
static int acf_iaxvar_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 9444 of file chan_iax2.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_var_assign(), ast_var_delete(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_var_t::entries, ast_datastore::inheritance, LOG_ERROR, ast_var_t::name, and var.

{
   struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
   AST_LIST_HEAD(, ast_var_t) *varlist;
   struct ast_var_t *var;

   if (!variablestore) {
      variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
      if (!variablestore) {
         ast_log(LOG_ERROR, "Memory allocation error\n");
         return -1;
      }
      varlist = ast_calloc(1, sizeof(*varlist));
      if (!varlist) {
         ast_log(LOG_ERROR, "Unable to assign new variable '%s'\n", data);
         return -1;
      }

      AST_LIST_HEAD_INIT(varlist);
      variablestore->data = varlist;
      variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
      ast_channel_datastore_add(chan, variablestore);
   } else
      varlist = variablestore->data;

   AST_LIST_LOCK(varlist);
   AST_LIST_TRAVERSE_SAFE_BEGIN(varlist, var, entries) {
      if (strcmp(var->name, data) == 0) {
         AST_LIST_REMOVE_CURRENT(entries);
         ast_var_delete(var);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;
   var = ast_var_assign(data, value);
   if (var)
      AST_LIST_INSERT_TAIL(varlist, var, entries);
   else
      ast_log(LOG_ERROR, "Unable to assign new variable '%s'\n", data);
   AST_LIST_UNLOCK(varlist);
   return 0;
}
static int add_calltoken_ignore ( const char *  addr) [static]

Definition at line 2370 of file chan_iax2.c.

References ao2_alloc, ao2_find, ao2_link, ao2_lock(), ao2_ref, ao2_unlock(), ast_append_ha(), ast_copy_ha(), ast_free_ha(), ast_log(), ast_strlen_zero(), addr_range::delme, addr_range::ha, LOG_WARNING, and OBJ_POINTER.

Referenced by set_config().

{
   struct addr_range tmp;
   struct addr_range *addr_range = NULL;
   struct ast_ha *ha = NULL;
   int error = 0;

   if (ast_strlen_zero(addr)) {
      ast_log(LOG_WARNING, "invalid calltokenoptional %s\n", addr);
      return -1;
   }

   ha = ast_append_ha("permit", addr, NULL, &error);

   /* check for valid config information */
   if (error) {
      ast_log(LOG_WARNING, "Error %d creating calltokenoptional entry %s\n", error, addr);
      return -1;
   }

   ast_copy_ha(ha, &tmp.ha);
   /* find or create the addr_range */
   if ((addr_range = ao2_find(calltoken_ignores, &tmp, OBJ_POINTER))) {
      ao2_lock(addr_range);
      addr_range->delme = 0;
      ao2_unlock(addr_range);
   } else if ((addr_range = ao2_alloc(sizeof(*addr_range), NULL))) {
      /* copy over config data into addr_range object */
      ast_copy_ha(ha, &addr_range->ha); /* this is safe because only one ha is possible */
      ao2_link(calltoken_ignores, addr_range);
   } else {
      ast_free_ha(ha);
      return -1;
   }

   ast_free_ha(ha);
   ao2_ref(addr_range, -1); /* decrement ref from ao2_find and ao2_alloc, only container ref remains */

   return 0;
}
static void add_empty_calltoken_ie ( struct chan_iax2_pvt pvt,
struct iax_ie_data ied 
) [static]

Definition at line 4533 of file chan_iax2.c.

References iax_ie_data::buf, chan_iax2_pvt::calltoken_ie_len, IAX_IE_CALLTOKEN, and iax_ie_data::pos.

Referenced by cache_get_callno_locked(), iax2_call(), iax2_do_register(), iax2_poke_peer(), and registry_rerequest().

{
   /* first make sure their are two empty bytes left in ied->buf */
   if (pvt && ied && (2 < ((int) sizeof(ied->buf) - ied->pos))) {
      ied->buf[ied->pos++] = IAX_IE_CALLTOKEN;  /* type */
      ied->buf[ied->pos++] = 0;   /* data size,  ZERO in this case */
      pvt->calltoken_ie_len = 2;
   }
}
static int addr_range_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2032 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, addr_range::ha, ast_ha::netaddr, and ast_ha::netmask.

Referenced by load_objects().

{
   struct addr_range *lim1 = obj, *lim2 = arg;
   return ((lim1->ha.netaddr.s_addr == lim2->ha.netaddr.s_addr) &&
      (lim1->ha.netmask.s_addr == lim2->ha.netmask.s_addr)) ?
      CMP_MATCH | CMP_STOP : 0;
}
static int addr_range_delme_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2019 of file chan_iax2.c.

References addr_range::delme.

Referenced by set_config_destroy().

{
   struct addr_range *lim = obj;
   lim->delme = 1;
   return 0;
}
static int addr_range_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 2026 of file chan_iax2.c.

References addr_range::ha, and ast_ha::netaddr.

Referenced by load_objects().

{
   const struct addr_range *lim = obj;
   return abs((int) lim->ha.netaddr.s_addr);
}
static int addr_range_match_address_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2052 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, addr_range::ha, ast_ha::netaddr, and ast_ha::netmask.

Referenced by calltoken_required(), and set_peercnt_limit().

{
   struct addr_range *addr_range = obj;
   struct sockaddr_in *sin = arg;

   if ((sin->sin_addr.s_addr & addr_range->ha.netmask.s_addr) == addr_range->ha.netaddr.s_addr) {
      return CMP_MATCH | CMP_STOP;
   }
   return 0;
}
static int apply_context ( struct iax2_context con,
const char *  context 
) [static]

Definition at line 7220 of file chan_iax2.c.

References iax2_context::context, and iax2_context::next.

Referenced by check_access().

{
   while(con) {
      if (!strcmp(con->context, context) || !strcmp(con->context, "*"))
         return -1;
      con = con->next;
   }
   return 0;
}
static int ast_cli_netstats ( struct mansession s,
int  fd,
int  limit_fmt 
) [static]

Definition at line 6925 of file chan_iax2.c.

References ACN_FORMAT1, ACN_FORMAT2, ARRAY_LEN, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, astman_append(), jb_info::current, iax_rr::delay, iax_rr::dropped, chan_iax2_pvt::first_iax_message, jb_info::frames_dropped, jb_info::frames_lost, jb_info::frames_ooo, chan_iax2_pvt::frames_received, iax_frame_subclass2str(), IAX_USEJITTERBUF, jb_getinfo(), iax_rr::jitter, jb_info::jitter, chan_iax2_pvt::last_iax_message, iax_rr::losscnt, iax_rr::losspct, jb_info::losspct, MARK_IAX_SUBCLASS_TX, jb_info::min, iax_rr::ooo, iax_rr::packets, chan_iax2_pvt::pingtime, and chan_iax2_pvt::remote_rr.

Referenced by handle_cli_iax2_show_netstats(), and manager_iax2_show_netstats().

{
   int x;
   int numchans = 0;
   char first_message[10] = { 0, };
   char last_message[10] = { 0, };
#define ACN_FORMAT1 "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
#define ACN_FORMAT2 "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
   for (x = 0; x < ARRAY_LEN(iaxs); x++) {
      ast_mutex_lock(&iaxsl[x]);
      if (iaxs[x]) {
         int localjitter, localdelay, locallost, locallosspct, localdropped, localooo;
         jb_info jbinfo;
         iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message));
         iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message));

         if(ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
            jb_getinfo(iaxs[x]->jb, &jbinfo);
            localjitter = jbinfo.jitter;
            localdelay = jbinfo.current - jbinfo.min;
            locallost = jbinfo.frames_lost;
            locallosspct = jbinfo.losspct/1000;
            localdropped = jbinfo.frames_dropped;
            localooo = jbinfo.frames_ooo;
         } else {
            localjitter = -1;
            localdelay = 0;
            locallost = -1;
            locallosspct = -1;
            localdropped = 0;
            localooo = -1;
         }
         if (s)
            astman_append(s, limit_fmt ? ACN_FORMAT1 : ACN_FORMAT2,
               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
               iaxs[x]->pingtime,
               localjitter,
               localdelay,
               locallost,
               locallosspct,
               localdropped,
               localooo,
               iaxs[x]->frames_received/1000,
               iaxs[x]->remote_rr.jitter,
               iaxs[x]->remote_rr.delay,
               iaxs[x]->remote_rr.losscnt,
               iaxs[x]->remote_rr.losspct,
               iaxs[x]->remote_rr.dropped,
               iaxs[x]->remote_rr.ooo,
               iaxs[x]->remote_rr.packets/1000,
               (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
               first_message,
               (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
               last_message);
         else
            ast_cli(fd, limit_fmt ? ACN_FORMAT1 : ACN_FORMAT2,
               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
               iaxs[x]->pingtime,
               localjitter,
               localdelay,
               locallost,
               locallosspct,
               localdropped,
               localooo,
               iaxs[x]->frames_received/1000,
               iaxs[x]->remote_rr.jitter,
               iaxs[x]->remote_rr.delay,
               iaxs[x]->remote_rr.losscnt,
               iaxs[x]->remote_rr.losspct,
               iaxs[x]->remote_rr.dropped,
               iaxs[x]->remote_rr.ooo,
               iaxs[x]->remote_rr.packets/1000,
               (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
               first_message,
               (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
               last_message);
         numchans++;
      }
      ast_mutex_unlock(&iaxsl[x]);
   }

   return numchans;
}
static struct ast_channel* ast_iax2_new ( int  callno,
int  state,
int  capability 
) [static, read]

Create new call, interface with the PBX core.

Definition at line 5448 of file chan_iax2.c.

References chan_iax2_pvt::accountcode, chan_iax2_pvt::adsi, ast_channel::adsicpe, ast_channel::amaflags, chan_iax2_pvt::amaflags, chan_iax2_pvt::ani, AST_ADSI_UNAVAILABLE, ast_best_codec(), ast_calloc, ast_channel_alloc(), ast_channel_datastore_add(), ast_channel_free(), ast_copy_string(), ast_datastore_alloc(), ast_datastore_free(), ast_debug, ast_free, ast_hangup(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log(), ast_module_ref(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), AST_STATE_DOWN, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_var_assign(), chan_iax2_pvt::calling_pres, chan_iax2_pvt::calling_tns, chan_iax2_pvt::calling_ton, chan_iax2_pvt::callno, CALLNO_TO_PTR, chan_iax2_pvt::capability, capability, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, chan_iax2_pvt::cid_name, chan_iax2_pvt::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, chan_iax2_pvt::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, chan_iax2_pvt::dnid, ast_var_t::entries, ast_channel::exten, chan_iax2_pvt::exten, chan_iax2_pvt::host, iax2_ami_channelupdate(), iax2_tech, chan_iax2_pvt::iaxvars, ast_datastore::inheritance, chan_iax2_pvt::language, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_variable::name, ast_channel::nativeformats, ast_variable::next, chan_iax2_pvt::owner, parkinglot, chan_iax2_pvt::parkinglot, pbx_builtin_setvar_helper(), chan_iax2_pvt::peeradsicpe, ast_channel::rawreadformat, ast_channel::rawwriteformat, chan_iax2_pvt::rdnis, ast_channel::readformat, ast_module_info::self, ast_channel::tech, ast_channel::tech_pvt, ast_variable::value, var, chan_iax2_pvt::vars, and ast_channel::writeformat.

Referenced by iax2_request(), and socket_process().

{
   struct ast_channel *tmp;
   struct chan_iax2_pvt *i;
   struct ast_variable *v = NULL;

   if (!(i = iaxs[callno])) {
      ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno);
      return NULL;
   }

   /* Don't hold call lock */
   ast_mutex_unlock(&iaxsl[callno]);
   tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
   ast_mutex_lock(&iaxsl[callno]);
   if (i != iaxs[callno]) {
      if (tmp) {
         /* unlock and relock iaxsl[callno] to preserve locking order */
         ast_mutex_unlock(&iaxsl[callno]);
         ast_channel_free(tmp);
         ast_mutex_lock(&iaxsl[callno]);
      }
      return NULL;
   }
   iax2_ami_channelupdate(i);
   if (!tmp)
      return NULL;
   tmp->tech = &iax2_tech;
   /* We can support any format by default, until we get restricted */
   tmp->nativeformats = capability;
   tmp->readformat = tmp->rawreadformat = ast_best_codec(capability);
   tmp->writeformat = tmp->rawwriteformat = ast_best_codec(capability);
   tmp->tech_pvt = CALLNO_TO_PTR(i->callno);

   if (!ast_strlen_zero(i->parkinglot))
      ast_string_field_set(tmp, parkinglot, i->parkinglot);
   /* Don't use ast_set_callerid() here because it will
    * generate a NewCallerID event before the NewChannel event */
   if (!ast_strlen_zero(i->ani))
      tmp->cid.cid_ani = ast_strdup(i->ani);
   else
      tmp->cid.cid_ani = ast_strdup(i->cid_num);
   tmp->cid.cid_dnid = ast_strdup(i->dnid);
   tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
   tmp->cid.cid_pres = i->calling_pres;
   tmp->cid.cid_ton = i->calling_ton;
   tmp->cid.cid_tns = i->calling_tns;
   if (!ast_strlen_zero(i->language))
      ast_string_field_set(tmp, language, i->language);
   if (!ast_strlen_zero(i->accountcode))
      ast_string_field_set(tmp, accountcode, i->accountcode);
   if (i->amaflags)
      tmp->amaflags = i->amaflags;
   ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
   ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
   if (i->adsi)
      tmp->adsicpe = i->peeradsicpe;
   else
      tmp->adsicpe = AST_ADSI_UNAVAILABLE;
   i->owner = tmp;
   i->capability = capability;

   /* Set inherited variables */
   if (i->vars) {
      for (v = i->vars ; v ; v = v->next)
         pbx_builtin_setvar_helper(tmp, v->name, v->value);
   }
   if (i->iaxvars) {
      struct ast_datastore *variablestore;
      struct ast_variable *var, *prev = NULL;
      AST_LIST_HEAD(, ast_var_t) *varlist;
      ast_debug(1, "Loading up the channel with IAXVARs\n");
      varlist = ast_calloc(1, sizeof(*varlist));
      variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
      if (variablestore && varlist) {
         variablestore->data = varlist;
         variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
         AST_LIST_HEAD_INIT(varlist);
         for (var = i->iaxvars; var; var = var->next) {
            struct ast_var_t *newvar = ast_var_assign(var->name, var->value);
            if (prev)
               ast_free(prev);
            prev = var;
            if (!newvar) {
               /* Don't abort list traversal, as this would leave i->iaxvars in an inconsistent state. */
               ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
            } else {
               AST_LIST_INSERT_TAIL(varlist, newvar, entries);
            }
         }
         if (prev)
            ast_free(prev);
         i->iaxvars = NULL;
         ast_channel_datastore_add(i->owner, variablestore);
      } else {
         if (variablestore) {
            ast_datastore_free(variablestore);
         }
         if (varlist) {
            ast_free(varlist);
         }
      }
   }

   if (state != AST_STATE_DOWN) {
      if (ast_pbx_start(tmp)) {
         ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
         ast_hangup(tmp);
         i->owner = NULL;
         return NULL;
      }
   }

   ast_module_ref(ast_module_info->self);
   return tmp;
}
static int attempt_transmit ( const void *  data) [static]

Definition at line 3406 of file chan_iax2.c.

References __attempt_transmit(), and schedule_action.

Referenced by __attempt_transmit(), and network_thread().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__attempt_transmit, data))
#endif      
      __attempt_transmit(data);
   return 0;
}
static int auth_fail ( int  callno,
int  failcode 
) [static]

Definition at line 8674 of file chan_iax2.c.

References auth_reject(), chan_iax2_pvt::authfail, chan_iax2_pvt::authid, and iax2_sched_replace().

Referenced by socket_process().

{
   /* Schedule sending the authentication failure in one second, to prevent
      guessing */
   if (iaxs[callno]) {
      iaxs[callno]->authfail = failcode;
      if (delayreject) {
         iaxs[callno]->authid = iax2_sched_replace(iaxs[callno]->authid, 
            sched, 1000, auth_reject, (void *)(long)callno);
      } else
         auth_reject((void *)(long)callno);
   }
   return 0;
}
static int auth_reject ( const void *  data) [static]

Definition at line 8660 of file chan_iax2.c.

References __auth_reject(), ast_mutex_lock(), ast_mutex_unlock(), chan_iax2_pvt::authid, and schedule_action.

Referenced by auth_fail().

{
   int callno = (int)(long)(data);
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno])
      iaxs[callno]->authid = -1;
   ast_mutex_unlock(&iaxsl[callno]);
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__auth_reject, data))
#endif      
      __auth_reject(data);
   return 0;
}
static int authenticate ( const char *  challenge,
const char *  secret,
const char *  keyn,
int  authmethods,
struct iax_ie_data ied,
struct sockaddr_in *  sin,
struct chan_iax2_pvt pvt 
) [static]

Definition at line 7788 of file chan_iax2.c.

References ast_inet_ntoa(), ast_key_get, AST_KEY_PRIVATE, ast_log(), ast_sign, ast_strlen_zero(), build_encryption_keys(), IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_AUTH_RSA, iax_ie_append_str(), IAX_IE_MD5_RESULT, IAX_IE_PASSWORD, IAX_IE_RSA_RESULT, LOG_NOTICE, MD5Final(), MD5Init(), and MD5Update().

Referenced by authenticate_reply(), and registry_rerequest().

{
   int res = -1;
   int x;
   if (!ast_strlen_zero(keyn)) {
      if (!(authmethods & IAX_AUTH_RSA)) {
         if (ast_strlen_zero(secret)) 
            ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(sin->sin_addr));
      } else if (ast_strlen_zero(challenge)) {
         ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(sin->sin_addr));
      } else {
         char sig[256];
         struct ast_key *key;
         key = ast_key_get(keyn, AST_KEY_PRIVATE);
         if (!key) {
            ast_log(LOG_NOTICE, "Unable to find private key '%s'\n", keyn);
         } else {
            if (ast_sign(key, (char*)challenge, sig)) {
               ast_log(LOG_NOTICE, "Unable to sign challenge with key\n");
               res = -1;
            } else {
               iax_ie_append_str(ied, IAX_IE_RSA_RESULT, sig);
               res = 0;
            }
         }
      }
   } 
   /* Fall back */
   if (res && !ast_strlen_zero(secret)) {
      if ((authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(challenge)) {
         struct MD5Context md5;
         unsigned char digest[16];
         char digres[128];
         MD5Init(&md5);
         MD5Update(&md5, (unsigned char *)challenge, strlen(challenge));
         MD5Update(&md5, (unsigned char *)secret, strlen(secret));
         MD5Final(digest, &md5);
         /* If they support md5, authenticate with it.  */
         for (x=0;x<16;x++)
            sprintf(digres + (x << 1),  "%2.2x", digest[x]); /* safe */
         if (pvt) {
            build_encryption_keys(digest, pvt);
         }
         iax_ie_append_str(ied, IAX_IE_MD5_RESULT, digres);
         res = 0;
      } else if (authmethods & IAX_AUTH_PLAINTEXT) {
         iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
         res = 0;
      } else
         ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_inet_ntoa(sin->sin_addr), authmethods);
   }
   return res;
}
static int authenticate_reply ( struct chan_iax2_pvt p,
struct sockaddr_in *  sin,
struct iax_ies ies,
const char *  override,
const char *  okey 
) [static]
Note:
This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno, so do not call this function with a pvt lock held.

Definition at line 7846 of file chan_iax2.c.

References iax2_peer::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_calloc, ast_channel_datastore_add(), ast_datastore_alloc(), ast_datastore_free(), AST_FRAME_IAX, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_var_assign(), authenticate(), iax_ies::authmethods, iax2_peer::authmethods, iax_ie_data::buf, chan_iax2_pvt::callno, chan_iax2_pvt::challenge, iax_ies::challenge, ast_datastore::data, DATASTORE_INHERIT_FOREVER, chan_iax2_pvt::encmethods, iax_ies::encmethods, ast_var_t::entries, IAX_AUTH_MD5, IAX_COMMAND_AUTHREP, IAX_ENCRYPTED, IAX_FORCE_ENCRYPT, IAX_KEYPOPULATED, ast_datastore::inheritance, LOG_ERROR, LOG_NOTICE, iax2_peer::mask, merge_encryption(), ast_variable::name, iax2_peer::name, ast_variable::next, iax2_peer::outkey, chan_iax2_pvt::owner, chan_iax2_pvt::peer, peer_unref(), iax_ie_data::pos, realtime_peer(), iax2_peer::secret, send_command(), chan_iax2_pvt::username, iax2_peer::username, iax_ies::username, ast_variable::value, var, and iax_ies::vars.

Referenced by socket_process().

{
   struct iax2_peer *peer = NULL;
   /* Start pessimistic */
   int res = -1;
   int authmethods = 0;
   struct iax_ie_data ied;
   uint16_t callno = p->callno;

   memset(&ied, 0, sizeof(ied));
   
   if (ies->username)
      ast_string_field_set(p, username, ies->username);
   if (ies->challenge)
      ast_string_field_set(p, challenge, ies->challenge);
   if (ies->authmethods)
      authmethods = ies->authmethods;
   if (authmethods & IAX_AUTH_MD5)
      merge_encryption(p, ies->encmethods);
   else
      p->encmethods = 0;

   /* Check for override RSA authentication first */
   if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
      /* Normal password authentication */
      res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, p);
   } else {
      struct ao2_iterator i = ao2_iterator_init(peers, 0);
      while ((peer = ao2_iterator_next(&i))) {
         if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name)) 
             /* No peer specified at our end, or this is the peer */
             && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
             /* No username specified in peer rule, or this is the right username */
             && (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
             /* No specified host, or this is our host */
            ) {
            res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, p);
            if (!res) {
               peer_unref(peer);
               break;
            }
         }
         peer_unref(peer);
      }
      ao2_iterator_destroy(&i);
      if (!peer) {
         /* We checked our list and didn't find one.  It's unlikely, but possible, 
            that we're trying to authenticate *to* a realtime peer */
         const char *peer_name = ast_strdupa(p->peer);
         ast_mutex_unlock(&iaxsl[callno]);
         if ((peer = realtime_peer(peer_name, NULL))) {
            ast_mutex_lock(&iaxsl[callno]);
            if (!(p = iaxs[callno])) {
               peer_unref(peer);
               return -1;
            }
            res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, p);
            peer_unref(peer);
         }
         if (!peer) {
            ast_mutex_lock(&iaxsl[callno]);
            if (!(p = iaxs[callno]))
               return -1;
         }
      }
   }

   if (ies->encmethods) {
      ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED);
   } else if (ast_test_flag(iaxs[callno], IAX_FORCE_ENCRYPT)) {
      ast_log(LOG_NOTICE, "Call initiated without encryption while forceencryption=yes option is set");
      return -1;             /* if force encryption is yes, and no encryption methods, then return -1 to hangup */
   }
   if (!res) {
      struct ast_datastore *variablestore;
      struct ast_variable *var, *prev = NULL;
      AST_LIST_HEAD(, ast_var_t) *varlist;
      varlist = ast_calloc(1, sizeof(*varlist));
      variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
      if (variablestore && varlist && p->owner) {
         variablestore->data = varlist;
         variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
         AST_LIST_HEAD_INIT(varlist);
         for (var = ies->vars; var; var = var->next) {
            struct ast_var_t *newvar = ast_var_assign(var->name, var->value);
            if (prev)
               ast_free(prev);
            prev = var;
            if (!newvar) {
               /* Don't abort list traversal, as this would leave ies->vars in an inconsistent state. */
               ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
            } else {
               AST_LIST_INSERT_TAIL(varlist, newvar, entries);
            }
         }
         if (prev)
            ast_free(prev);
         ies->vars = NULL;
         ast_channel_datastore_add(p->owner, variablestore);
      } else {
         if (p->owner)
            ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
         if (variablestore)
            ast_datastore_free(variablestore);
         if (varlist)
            ast_free(varlist);
      }
   }

   if (!res)
      res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
   return res;
}
static int authenticate_request ( int  call_num) [static]
Precondition:
iaxsl[call_num] is locked
Note:
Since this function calls send_command_final(), the pvt struct for the given call number may disappear while executing this function.

Definition at line 7496 of file chan_iax2.c.

References ao2_find, AST_CAUSE_CALL_REJECTED, AST_FRAME_IAX, ast_random(), ast_set_flag, ast_string_field_set, ast_test_flag, chan_iax2_pvt::authmethods, iax_ie_data::buf, chan_iax2_pvt::challenge, iax2_user::curauthreq, chan_iax2_pvt::encmethods, IAX_AUTH_MD5, IAX_AUTH_RSA, IAX_COMMAND_AUTHREQ, IAX_COMMAND_REJECT, IAX_ENCRYPTED, iax_ie_append_byte(), iax_ie_append_short(), iax_ie_append_str(), IAX_IE_AUTHMETHODS, IAX_IE_CAUSE, IAX_IE_CAUSECODE, IAX_IE_CHALLENGE, IAX_IE_ENCRYPTION, IAX_IE_USERNAME, IAX_MAXAUTHREQ, iax2_user::maxauthreq, OBJ_POINTER, iax_ie_data::pos, send_command(), send_command_final(), user, user_unref(), and chan_iax2_pvt::username.

Referenced by socket_process().

{
   struct iax_ie_data ied;
   int res = -1, authreq_restrict = 0;
   char challenge[10];
   struct chan_iax2_pvt *p = iaxs[call_num];

   memset(&ied, 0, sizeof(ied));

   /* If an AUTHREQ restriction is in place, make sure we can send an AUTHREQ back */
   if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
      struct iax2_user *user, tmp_user = {
         .name = p->username, 
      };

      user = ao2_find(users, &tmp_user, OBJ_POINTER);
      if (user) {
         if (user->curauthreq == user->maxauthreq)
            authreq_restrict = 1;
         else
            user->curauthreq++;
         user = user_unref(user);
      }
   }

   /* If the AUTHREQ limit test failed, send back an error */
   if (authreq_restrict) {
      iax_ie_append_str(&ied, IAX_IE_CAUSE, "Unauthenticated call limit reached");
      iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, AST_CAUSE_CALL_REJECTED);
      send_command_final(p, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
      return 0;
   }

   iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
   if (p->authmethods & (IAX_AUTH_MD5 | IAX_AUTH_RSA)) {
      snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
      ast_string_field_set(p, challenge, challenge);
      /* snprintf(p->challenge, sizeof(p->challenge), "%d", (int)ast_random()); */
      iax_ie_append_str(&ied, IAX_IE_CHALLENGE, p->challenge);
   }
   if (p->encmethods)
      iax_ie_append_short(&ied, IAX_IE_ENCRYPTION, p->encmethods);

   iax_ie_append_str(&ied,IAX_IE_USERNAME, p->username);

   res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREQ, 0, ied.buf, ied.pos, -1);

   if (p->encmethods)
      ast_set_flag(p, IAX_ENCRYPTED);

   return res;
}
static int authenticate_verify ( struct chan_iax2_pvt p,
struct iax_ies ies 
) [static]

Definition at line 7549 of file chan_iax2.c.

References ao2_find, ast_atomic_fetchadd_int(), ast_check_signature, ast_clear_flag, ast_copy_string(), ast_key_get, AST_KEY_PUBLIC, ast_log(), ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, chan_iax2_pvt::authmethods, chan_iax2_pvt::authrej, chan_iax2_pvt::challenge, iax2_user::curauthreq, chan_iax2_pvt::encmethods, IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_AUTH_RSA, IAX_FORCE_ENCRYPT, IAX_MAXAUTHREQ, IAX_STATE_AUTHENTICATED, chan_iax2_pvt::inkeys, LOG_NOTICE, LOG_WARNING, iax_ies::md5_result, MD5Final(), MD5Init(), MD5Update(), iax2_user::name, OBJ_POINTER, iax_ies::password, iax_ies::rsa_result, chan_iax2_pvt::secret, secret, chan_iax2_pvt::state, strsep(), user, user_unref(), and chan_iax2_pvt::username.

Referenced by socket_process().

{
   char requeststr[256];
   char md5secret[256] = "";
   char secret[256] = "";
   char rsasecret[256] = "";
   int res = -1; 
   int x;
   struct iax2_user *user, tmp_user = {
      .name = p->username, 
   };

   if (p->authrej) {
      return res;
   }
   user = ao2_find(users, &tmp_user, OBJ_POINTER);
   if (user) {
      if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
         ast_atomic_fetchadd_int(&user->curauthreq, -1);
         ast_clear_flag(p, IAX_MAXAUTHREQ);
      }
      ast_string_field_set(p, host, user->name);
      user = user_unref(user);
   }
   if (ast_test_flag(p, IAX_FORCE_ENCRYPT) && !p->encmethods) { 
      ast_log(LOG_NOTICE, "Call Terminated, Incoming call is unencrypted while force encrypt is enabled.");
      return res;
   }
   if (!ast_test_flag(&p->state, IAX_STATE_AUTHENTICATED))
      return res;
   if (ies->password)
      ast_copy_string(secret, ies->password, sizeof(secret));
   if (ies->md5_result)
      ast_copy_string(md5secret, ies->md5_result, sizeof(md5secret));
   if (ies->rsa_result)
      ast_copy_string(rsasecret, ies->rsa_result, sizeof(rsasecret));
   if ((p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(rsasecret) && !ast_strlen_zero(p->inkeys)) {
      struct ast_key *key;
      char *keyn;
      char tmpkey[256];
      char *stringp=NULL;
      ast_copy_string(tmpkey, p->inkeys, sizeof(tmpkey));
      stringp=tmpkey;
      keyn = strsep(&stringp, ":");
      while(keyn) {
         key = ast_key_get(keyn, AST_KEY_PUBLIC);
         if (key && !ast_check_signature(key, p->challenge, rsasecret)) {
            res = 0;
            break;
         } else if (!key)
            ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
         keyn = strsep(&stringp, ":");
      }
   } else if (p->authmethods & IAX_AUTH_MD5) {
      struct MD5Context md5;
      unsigned char digest[16];
      char *tmppw, *stringp;
      
      tmppw = ast_strdupa(p->secret);
      stringp = tmppw;
      while((tmppw = strsep(&stringp, ";"))) {
         MD5Init(&md5);
         MD5Update(&md5, (unsigned char *)p->challenge, strlen(p->challenge));
         MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
         MD5Final(digest, &md5);
         /* If they support md5, authenticate with it.  */
         for (x=0;x<16;x++)
            sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
         if (!strcasecmp(requeststr, md5secret)) {
            res = 0;
            break;
         }
      }
   } else if (p->authmethods & IAX_AUTH_PLAINTEXT) {
      if (!strcmp(secret, p->secret))
         res = 0;
   }
   return res;
}
static int auto_congest ( const void *  data) [static]

Definition at line 4472 of file chan_iax2.c.

References __auto_congest(), and schedule_action.

Referenced by iax2_call().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__auto_congest, data))
#endif      
      __auto_congest(data);
   return 0;
}
static int auto_hangup ( const void *  data) [static]

Definition at line 8704 of file chan_iax2.c.

References __auto_hangup(), ast_mutex_lock(), ast_mutex_unlock(), chan_iax2_pvt::autoid, and schedule_action.

Referenced by iax2_dprequest(), and iax2_provision().

{
   int callno = (int)(long)(data);
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      iaxs[callno]->autoid = -1;
   }
   ast_mutex_unlock(&iaxsl[callno]);
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__auto_hangup, data))
#endif      
      __auto_hangup(data);
   return 0;
}
static void build_callno_limits ( struct ast_variable v) [static]

Definition at line 2315 of file chan_iax2.c.

References ao2_alloc, ao2_find, ao2_link, ao2_lock(), ao2_ref, ao2_unlock(), ast_append_ha(), ast_copy_ha(), ast_free_ha(), ast_log(), addr_range::delme, addr_range::ha, addr_range::limit, LOG_ERROR, ast_variable::name, ast_variable::next, OBJ_POINTER, and ast_variable::value.

Referenced by set_config().

{
   struct addr_range *addr_range = NULL;
   struct addr_range tmp;
   struct ast_ha *ha;
   int limit;
   int error;
   int found;

   for (; v; v = v->next) {
      limit = -1;
      error = 0;
      found = 0;
      ha = ast_append_ha("permit", v->name, NULL, &error);

      /* check for valid config information */
      if (error) {
         ast_log(LOG_ERROR, "Call number limit for %s could not be added, Invalid address range\n.", v->name);
         continue;
      } else if ((sscanf(v->value, "%d", &limit) != 1) || (limit < 0)) {
         ast_log(LOG_ERROR, "Call number limit for %s could not be added. Invalid limit %s\n.", v->name, v->value);
         ast_free_ha(ha);
         continue;
      }

      ast_copy_ha(ha, &tmp.ha);
      /* find or create the addr_range */
      if ((addr_range = ao2_find(callno_limits, &tmp, OBJ_POINTER))) {
         ao2_lock(addr_range);
         found = 1;
      } else if (!(addr_range = ao2_alloc(sizeof(*addr_range), NULL))) {
         ast_free_ha(ha);
         return; /* out of memory */
      }

      /* copy over config data into addr_range object */
      ast_copy_ha(ha, &addr_range->ha); /* this is safe because only one ha is possible for each limit */
      ast_free_ha(ha); /* cleanup the tmp ha */
      addr_range->limit = limit;
      addr_range->delme = 0;

      /* cleanup */
      if (found) {
         ao2_unlock(addr_range);
      } else {
         ao2_link(callno_limits, addr_range);
      }
      ao2_ref(addr_range, -1); /* decrement ref from ao2_find and ao2_alloc, only container ref remains */
   }
}
static struct iax2_context* build_context ( const char *  context) [static, read]

Definition at line 11785 of file chan_iax2.c.

References ast_calloc, ast_copy_string(), and iax2_context::context.

Referenced by build_user().

{
   struct iax2_context *con;

   if ((con = ast_calloc(1, sizeof(*con))))
      ast_copy_string(con->context, context, sizeof(con->context));
   
   return con;
}
static void build_ecx_key ( const unsigned char *  digest,
struct chan_iax2_pvt pvt 
) [static]

Definition at line 5906 of file chan_iax2.c.

References build_rand_pad(), chan_iax2_pvt::ecx, chan_iax2_pvt::mydcx, and chan_iax2_pvt::semirand.

Referenced by build_encryption_keys(), and iax2_key_rotate().

{
   /* it is required to hold the corresponding decrypt key to our encrypt key
    * in the pvt struct because queued frames occasionally need to be decrypted and
    * re-encrypted when updated for a retransmission */
   build_rand_pad(pvt->semirand, sizeof(pvt->semirand));
   ast_aes_encrypt_key(digest, &pvt->ecx);
   ast_aes_decrypt_key(digest, &pvt->mydcx);
}
static void build_encryption_keys ( const unsigned char *  digest,
struct chan_iax2_pvt pvt 
) [static]

Definition at line 5900 of file chan_iax2.c.

References build_ecx_key(), and chan_iax2_pvt::dcx.

Referenced by authenticate(), and decrypt_frame().

{
   build_ecx_key(digest, pvt);
   ast_aes_decrypt_key(digest, &pvt->dcx);
}
static struct iax2_peer * build_peer ( const char *  name,
struct ast_variable v,
struct ast_variable alt,
int  temponly 
) [static, read]

Create peer structure based on configuration.

Definition at line 11933 of file chan_iax2.c.

References iax2_peer::addr, adsi, iax2_peer::adsi, ao2_alloc, ao2_find, ast_append_ha(), ast_callerid_split(), ast_clear_flag, ast_copy_flags, ast_dnsmgr_lookup(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_event_subscribe(), ast_false(), ast_free_ha(), ast_get_ip(), ast_log(), ast_parse_allow_disallow(), ast_sched_thread_del, ast_set2_flag, ast_set_flag, ast_set_flags_to, ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_true(), iax2_peer::authmethods, CALLTOKEN_AUTO, CALLTOKEN_DEFAULT, CALLTOKEN_NO, iax2_peer::calltoken_required, CALLTOKEN_YES, iax2_peer::capability, cid_name, cid_num, context, iax2_peer::dbsecret, iax2_peer::defaddr, DEFAULT_FREQ_NOTOK, DEFAULT_FREQ_OK, DEFAULT_MAXMS, defaultsockfd, iax2_peer::dnsmgr, iax2_peer::encmethods, iax2_peer::expire, iax2_peer::expiry, get_auth_methods(), get_encrypt_methods(), iax2_peer::ha, iax2_capability, iax2_encryption, IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_DEFAULT_PORTNO, IAX_DELME, IAX_DYNAMIC, IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_HASCALLERID, IAX_NOTRANSFER, IAX_SENDANI, IAX_TRANSFERMEDIA, IAX_TRUNK, IAX_USEJITTERBUF, inet_aton(), iax2_peer::inkeys, ast_variable::lineno, LOG_WARNING, iax2_peer::mailbox, mailbox, iax2_peer::mask, iax2_peer::maxcallno, iax2_peer::maxms, min_reg_expire, mwi_event_cb(), iax2_peer::mwi_event_sub, ast_variable::name, name, iax2_peer::name, ast_variable::next, OBJ_POINTER, iax2_peer::outkey, peer_destructor(), peer_set_srcaddr(), peer_unref(), peercnt_modify(), iax2_peer::peercontext, iax2_peer::pokeexpire, iax2_peer::pokefreqnotok, iax2_peer::pokefreqok, prefs, iax2_peer::prefs, iax2_peer::regexten, S_OR, secret, iax2_peer::smoothing, iax2_peer::sockfd, strsep(), unlink_peer(), ast_variable::value, and zonetag.

Referenced by realtime_peer(), and set_config().

{
   struct iax2_peer *peer = NULL;
   struct ast_ha *oldha = NULL;
   int maskfound = 0;
   int found = 0;
   int firstpass = 1;
   struct iax2_peer tmp_peer = {
      .name = name,
   };

   if (!temponly) {
      peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
      if (peer && !ast_test_flag(peer, IAX_DELME))
         firstpass = 0;
   }

   if (peer) {
      found++;
      if (firstpass) {
         oldha = peer->ha;
         peer->ha = NULL;
      }
      unlink_peer(peer);
   } else if ((peer = ao2_alloc(sizeof(*peer), peer_destructor))) {
      peer->expire = -1;
      peer->pokeexpire = -1;
      peer->sockfd = defaultsockfd;
      if (ast_string_field_init(peer, 32))
         peer = peer_unref(peer);
   }

   if (peer) {
      if (firstpass) {
         ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
         peer->encmethods = iax2_encryption;
         peer->adsi = adsi;
         ast_string_field_set(peer,secret,"");
         if (!found) {
            ast_string_field_set(peer, name, name);
            peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
            peer->expiry = min_reg_expire;
         }
         peer->prefs = prefs;
         peer->capability = iax2_capability;
         peer->smoothing = 0;
         peer->pokefreqok = DEFAULT_FREQ_OK;
         peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
         peer->maxcallno = 0;
         peercnt_modify(0, 0, &peer->addr);
         peer->calltoken_required = CALLTOKEN_DEFAULT;
         ast_string_field_set(peer,context,"");
         ast_string_field_set(peer,peercontext,"");
         ast_clear_flag(peer, IAX_HASCALLERID);
         ast_string_field_set(peer, cid_name, "");
         ast_string_field_set(peer, cid_num, "");
         ast_string_field_set(peer, mohinterpret, mohinterpret);
         ast_string_field_set(peer, mohsuggest, mohsuggest);
      }

      if (!v) {
         v = alt;
         alt = NULL;
      }
      while(v) {
         if (!strcasecmp(v->name, "secret")) {
            ast_string_field_set(peer, secret, v->value);
         } else if (!strcasecmp(v->name, "mailbox")) {
            ast_string_field_set(peer, mailbox, v->value);
         } else if (!strcasecmp(v->name, "hasvoicemail")) {
            if (ast_true(v->value) && ast_strlen_zero(peer->mailbox)) {
               ast_string_field_set(peer, mailbox, name);
            }
         } else if (!strcasecmp(v->name, "mohinterpret")) {
            ast_string_field_set(peer, mohinterpret, v->value);
         } else if (!strcasecmp(v->name, "mohsuggest")) {
            ast_string_field_set(peer, mohsuggest, v->value);
         } else if (!strcasecmp(v->name, "dbsecret")) {
            ast_string_field_set(peer, dbsecret, v->value);
         } else if (!strcasecmp(v->name, "trunk")) {
            ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);   
            if (ast_test_flag(peer, IAX_TRUNK) && !timer) {
               ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name);
               ast_clear_flag(peer, IAX_TRUNK);
            }
         } else if (!strcasecmp(v->name, "auth")) {
            peer->authmethods = get_auth_methods(v->value);
         } else if (!strcasecmp(v->name, "encryption")) {
            peer->encmethods |= get_encrypt_methods(v->value);
            if (!peer->encmethods) {
               ast_clear_flag(peer, IAX_FORCE_ENCRYPT);
            }
         } else if (!strcasecmp(v->name, "forceencryption")) {
            if (ast_false(v->value)) {
               ast_clear_flag(peer, IAX_FORCE_ENCRYPT);
            } else {
               peer->encmethods |= get_encrypt_methods(v->value);
               if (peer->encmethods) {
                  ast_set_flag(peer, IAX_FORCE_ENCRYPT);
               }
            }
         } else if (!strcasecmp(v->name, "transfer")) {
            if (!strcasecmp(v->value, "mediaonly")) {
               ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);  
            } else if (ast_true(v->value)) {
               ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
            } else 
               ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
         } else if (!strcasecmp(v->name, "jitterbuffer")) {
            ast_set2_flag(peer, ast_true(v->value), IAX_USEJITTERBUF);  
         } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
            ast_set2_flag(peer, ast_true(v->value), IAX_FORCEJITTERBUF);   
         } else if (!strcasecmp(v->name, "host")) {
            if (!strcasecmp(v->value, "dynamic")) {
               /* They'll register with us */
               ast_set_flag(peer, IAX_DYNAMIC); 
               if (!found) {
                  /* Initialize stuff iff we're not found, otherwise
                     we keep going with what we had */
                  memset(&peer->addr.sin_addr, 0, 4);
                  if (peer->addr.sin_port) {
                     /* If we've already got a port, make it the default rather than absolute */
                     peer->defaddr.sin_port = peer->addr.sin_port;
                     peer->addr.sin_port = 0;
                  }
               }
            } else {
               /* Non-dynamic.  Make sure we become that way if we're not */
               ast_sched_thread_del(sched, peer->expire);
               ast_clear_flag(peer, IAX_DYNAMIC);
               if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL))
                  return peer_unref(peer);
               if (!peer->addr.sin_port)
                  peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
            }
            if (!maskfound)
               inet_aton("255.255.255.255", &peer->mask);
         } else if (!strcasecmp(v->name, "defaultip")) {
            if (ast_get_ip(&peer->defaddr, v->value))
               return peer_unref(peer);
         } else if (!strcasecmp(v->name, "sourceaddress")) {
            peer_set_srcaddr(peer, v->value);
         } else if (!strcasecmp(v->name, "permit") ||
                  !strcasecmp(v->name, "deny")) {
            peer->ha = ast_append_ha(v->name, v->value, peer->ha, NULL);
         } else if (!strcasecmp(v->name, "mask")) {
            maskfound++;
            inet_aton(v->value, &peer->mask);
         } else if (!strcasecmp(v->name, "context")) {
            ast_string_field_set(peer, context, v->value);
         } else if (!strcasecmp(v->name, "regexten")) {
            ast_string_field_set(peer, regexten, v->value);
         } else if (!strcasecmp(v->name, "peercontext")) {
            ast_string_field_set(peer, peercontext, v->value);
         } else if (!strcasecmp(v->name, "port")) {
            if (ast_test_flag(peer, IAX_DYNAMIC))
               peer->defaddr.sin_port = htons(atoi(v->value));
            else
               peer->addr.sin_port = htons(atoi(v->value));
         } else if (!strcasecmp(v->name, "username")) {
            ast_string_field_set(peer, username, v->value);
         } else if (!strcasecmp(v->name, "allow")) {
            ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
         } else if (!strcasecmp(v->name, "disallow")) {
            ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
         } else if (!strcasecmp(v->name, "callerid")) {
            if (!ast_strlen_zero(v->value)) {
               char name2[80];
               char num2[80];
               ast_callerid_split(v->value, name2, sizeof(name2), num2, sizeof(num2));
               ast_string_field_set(peer, cid_name, name2);
               ast_string_field_set(peer, cid_num, num2);
            } else {
               ast_string_field_set(peer, cid_name, "");
               ast_string_field_set(peer, cid_num, "");
            }
            ast_set_flag(peer, IAX_HASCALLERID);
         } else if (!strcasecmp(v->name, "fullname")) {
            ast_string_field_set(peer, cid_name, S_OR(v->value, ""));
            ast_set_flag(peer, IAX_HASCALLERID);
         } else if (!strcasecmp(v->name, "cid_number")) {
            ast_string_field_set(peer, cid_num, S_OR(v->value, ""));
            ast_set_flag(peer, IAX_HASCALLERID);
         } else if (!strcasecmp(v->name, "sendani")) {
            ast_set2_flag(peer, ast_true(v->value), IAX_SENDANI); 
         } else if (!strcasecmp(v->name, "inkeys")) {
            ast_string_field_set(peer, inkeys, v->value);
         } else if (!strcasecmp(v->name, "outkey")) {
            ast_string_field_set(peer, outkey, v->value);
         } else if (!strcasecmp(v->name, "qualify")) {
            if (!strcasecmp(v->value, "no")) {
               peer->maxms = 0;
            } else if (!strcasecmp(v->value, "yes")) {
               peer->maxms = DEFAULT_MAXMS;
            } else if (sscanf(v->value, "%30d", &peer->maxms) != 1) {
               ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
               peer->maxms = 0;
            }
         } else if (!strcasecmp(v->name, "qualifysmoothing")) {
            peer->smoothing = ast_true(v->value);
         } else if (!strcasecmp(v->name, "qualifyfreqok")) {
            if (sscanf(v->value, "%30d", &peer->pokefreqok) != 1) {
               ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when OK should a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
            }
         } else if (!strcasecmp(v->name, "qualifyfreqnotok")) {
            if (sscanf(v->value, "%30d", &peer->pokefreqnotok) != 1) {
               ast_log(LOG_WARNING, "Qualification testing frequency of peer '%s' when NOT OK should be a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
            } else ast_log(LOG_WARNING, "Set peer->pokefreqnotok to %d\n", peer->pokefreqnotok);
         } else if (!strcasecmp(v->name, "timezone")) {
            ast_string_field_set(peer, zonetag, v->value);
         } else if (!strcasecmp(v->name, "adsi")) {
            peer->adsi = ast_true(v->value);
         } else if (!strcasecmp(v->name, "maxcallnumbers")) {
            if (sscanf(v->value, "%10hu", &peer->maxcallno) != 1) {
               ast_log(LOG_WARNING, "maxcallnumbers must be set to a valid number. %s is not valid at line %d.\n", v->value, v->lineno);
            } else {
               peercnt_modify(1, peer->maxcallno, &peer->addr);
            }
         } else if (!strcasecmp(v->name, "requirecalltoken")) {
            /* default is required unless in optional ip list */
            if (ast_false(v->value)) {
               peer->calltoken_required = CALLTOKEN_NO;
            } else if (!strcasecmp(v->value, "auto")) {
               peer->calltoken_required = CALLTOKEN_AUTO;
            } else if (ast_true(v->value)) {
               peer->calltoken_required = CALLTOKEN_YES;
            } else {
               ast_log(LOG_WARNING, "requirecalltoken must be set to a valid value. at line %d\n", v->lineno);
            }
         } /* else if (strcasecmp(v->name,"type")) */
         /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
         v = v->next;
         if (!v) {
            v = alt;
            alt = NULL;
         }
      }
      if (!peer->authmethods)
         peer->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
      ast_clear_flag(peer, IAX_DELME); 
      /* Make sure these are IPv4 addresses */
      peer->addr.sin_family = AF_INET;
   }

   if (oldha)
      ast_free_ha(oldha);

   if (!ast_strlen_zero(peer->mailbox)) {
      char *mailbox, *context;
      context = mailbox = ast_strdupa(peer->mailbox);
      strsep(&context, "@");
      if (ast_strlen_zero(context))
         context = "default";
      peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
         AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
         AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
         AST_EVENT_IE_END);
   }

   return peer;
}
static void build_rand_pad ( unsigned char *  buf,
ssize_t  len 
) [static]

Definition at line 5890 of file chan_iax2.c.

References ast_random().

Referenced by build_ecx_key(), and update_packet().

{
   long tmp;
   for (tmp = ast_random(); len > 0; tmp = ast_random()) {
      memcpy(buf, (unsigned char *) &tmp, (len > sizeof(tmp)) ? sizeof(tmp) : len);
      buf += sizeof(tmp);
      len -= sizeof(tmp);
   }
}
static struct iax2_user * build_user ( const char *  name,
struct ast_variable v,
struct ast_variable alt,
int  temponly 
) [static, read]

Create in-memory user structure from configuration.

Definition at line 12209 of file chan_iax2.c.

References adsi, iax2_user::adsi, iax2_user::amaflags, ao2_alloc, ao2_find, ao2_unlink, ast_append_ha(), ast_callerid_split(), ast_cdr_amaflags2int(), ast_clear_flag, ast_copy_flags, ast_false(), ast_free_ha(), ast_log(), ast_parse_allow_disallow(), ast_set2_flag, ast_set_flag, ast_set_flags_to, ast_strdupa, ast_string_field_build, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_true(), ast_variable_new(), iax2_user::authmethods, build_context(), CALLTOKEN_AUTO, CALLTOKEN_DEFAULT, CALLTOKEN_NO, iax2_user::calltoken_required, CALLTOKEN_YES, iax2_user::capability, iax2_user::cid_name, cid_name, iax2_user::cid_num, cid_num, cleanup(), iax2_user::contexts, iax2_user::curauthreq, iax2_user::dbsecret, iax2_user::encmethods, format, free_context(), get_auth_methods(), get_encrypt_methods(), iax2_user::ha, iax2_capability, iax2_encryption, IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_AUTH_RSA, IAX_CODEC_NOCAP, IAX_CODEC_NOPREFS, IAX_CODEC_USER_FIRST, IAX_DELME, IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_HASCALLERID, IAX_IMMEDIATE, IAX_NOTRANSFER, IAX_TRANSFERMEDIA, IAX_TRUNK, IAX_USEJITTERBUF, iax2_user::inkeys, ast_variable::lineno, LOG_WARNING, maxauthreq, iax2_user::maxauthreq, ast_variable::name, name, iax2_user::name, ast_variable::next, iax2_context::next, OBJ_POINTER, parkinglot, prefs, iax2_user::prefs, secret, iax2_user::secret, user, user_destructor(), user_unref(), ast_variable::value, and iax2_user::vars.

Referenced by realtime_user(), and set_config().

{
   struct iax2_user *user = NULL;
   struct iax2_context *con, *conl = NULL;
   struct ast_ha *oldha = NULL;
   struct iax2_context *oldcon = NULL;
   int format;
   int firstpass=1;
   int oldcurauthreq = 0;
   char *varname = NULL, *varval = NULL;
   struct ast_variable *tmpvar = NULL;
   struct iax2_user tmp_user = {
      .name = name,
   };

   if (!temponly) {
      user = ao2_find(users, &tmp_user, OBJ_POINTER);
      if (user && !ast_test_flag(user, IAX_DELME))
         firstpass = 0;
   }

   if (user) {
      if (firstpass) {
         oldcurauthreq = user->curauthreq;
         oldha = user->ha;
         oldcon = user->contexts;
         user->ha = NULL;
         user->contexts = NULL;
      }
      /* Already in the list, remove it and it will be added back (or FREE'd) */
      ao2_unlink(users, user);
   } else {
      user = ao2_alloc(sizeof(*user), user_destructor);
   }
   
   if (user) {
      if (firstpass) {
         ast_string_field_free_memory(user);
         memset(user, 0, sizeof(struct iax2_user));
         if (ast_string_field_init(user, 32)) {
            user = user_unref(user);
            goto cleanup;
         }
         user->maxauthreq = maxauthreq;
         user->curauthreq = oldcurauthreq;
         user->prefs = prefs;
         user->capability = iax2_capability;
         user->encmethods = iax2_encryption;
         user->adsi = adsi;
         user->calltoken_required = CALLTOKEN_DEFAULT;
         ast_string_field_set(user, name, name);
         ast_string_field_set(user, language, language);
         ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT); 
         ast_clear_flag(user, IAX_HASCALLERID);
         ast_string_field_set(user, cid_name, "");
         ast_string_field_set(user, cid_num, "");
         ast_string_field_set(user, accountcode, accountcode);
         ast_string_field_set(user, mohinterpret, mohinterpret);
         ast_string_field_set(user, mohsuggest, mohsuggest);
      }
      if (!v) {
         v = alt;
         alt = NULL;
      }
      while(v) {
         if (!strcasecmp(v->name, "context")) {
            con = build_context(v->value);
            if (con) {
               if (conl)
                  conl->next = con;
               else
                  user->contexts = con;
               conl = con;
            }
         } else if (!strcasecmp(v->name, "permit") ||
                  !strcasecmp(v->name, "deny")) {
            user->ha = ast_append_ha(v->name, v->value, user->ha, NULL);
         } else if (!strcasecmp(v->name, "setvar")) {
            varname = ast_strdupa(v->value);
            if (varname && (varval = strchr(varname,'='))) {
               *varval = '\0';
               varval++;
               if((tmpvar = ast_variable_new(varname, varval, ""))) {
                  tmpvar->next = user->vars; 
                  user->vars = tmpvar;
               }
            }
         } else if (!strcasecmp(v->name, "allow")) {
            ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
         } else if (!strcasecmp(v->name, "disallow")) {
            ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
         } else if (!strcasecmp(v->name, "trunk")) {
            ast_set2_flag(user, ast_true(v->value), IAX_TRUNK);   
            if (ast_test_flag(user, IAX_TRUNK) && !timer) {
               ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name);
               ast_clear_flag(user, IAX_TRUNK);
            }
         } else if (!strcasecmp(v->name, "auth")) {
            user->authmethods = get_auth_methods(v->value);
         } else if (!strcasecmp(v->name, "encryption")) {
            user->encmethods |= get_encrypt_methods(v->value);
            if (!user->encmethods) {
               ast_clear_flag(user, IAX_FORCE_ENCRYPT);
            }
         } else if (!strcasecmp(v->name, "forceencryption")) {
            if (ast_false(v->value)) {
               ast_clear_flag(user, IAX_FORCE_ENCRYPT);
            } else {
               user->encmethods |= get_encrypt_methods(v->value);
               if (user->encmethods) {
                  ast_set_flag(user, IAX_FORCE_ENCRYPT);
               }
            }
         } else if (!strcasecmp(v->name, "transfer")) {
            if (!strcasecmp(v->value, "mediaonly")) {
               ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);  
            } else if (ast_true(v->value)) {
               ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
            } else 
               ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
         } else if (!strcasecmp(v->name, "codecpriority")) {
            if(!strcasecmp(v->value, "caller"))
               ast_set_flag(user, IAX_CODEC_USER_FIRST);
            else if(!strcasecmp(v->value, "disabled"))
               ast_set_flag(user, IAX_CODEC_NOPREFS);
            else if(!strcasecmp(v->value, "reqonly")) {
               ast_set_flag(user, IAX_CODEC_NOCAP);
               ast_set_flag(user, IAX_CODEC_NOPREFS);
            }
         } else if (!strcasecmp(v->name, "immediate")) {
            ast_set2_flag(user, ast_true(v->value), IAX_IMMEDIATE);
         } else if (!strcasecmp(v->name, "jitterbuffer")) {
            ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF);
         } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
            ast_set2_flag(user, ast_true(v->value), IAX_FORCEJITTERBUF);
         } else if (!strcasecmp(v->name, "dbsecret")) {
            ast_string_field_set(user, dbsecret, v->value);
         } else if (!strcasecmp(v->name, "secret")) {
            if (!ast_strlen_zero(user->secret)) {
               char *old = ast_strdupa(user->secret);

               ast_string_field_build(user, secret, "%s;%s", old, v->value);
            } else
               ast_string_field_set(user, secret, v->value);
         } else if (!strcasecmp(v->name, "callerid")) {
            if (!ast_strlen_zero(v->value) && strcasecmp(v->value, "asreceived")) {
               char name2[80];
               char num2[80];
               ast_callerid_split(v->value, name2, sizeof(name2), num2, sizeof(num2));
               ast_string_field_set(user, cid_name, name2);
               ast_string_field_set(user, cid_num, num2);
               ast_set_flag(user, IAX_HASCALLERID);
            } else {
               ast_clear_flag(user, IAX_HASCALLERID);
               ast_string_field_set(user, cid_name, "");
               ast_string_field_set(user, cid_num, "");
            }
         } else if (!strcasecmp(v->name, "fullname")) {
            if (!ast_strlen_zero(v->value)) {
               ast_string_field_set(user, cid_name, v->value);
               ast_set_flag(user, IAX_HASCALLERID);
            } else {
               ast_string_field_set(user, cid_name, "");
               if (ast_strlen_zero(user->cid_num))
                  ast_clear_flag(user, IAX_HASCALLERID);
            }
         } else if (!strcasecmp(v->name, "cid_number")) {
            if (!ast_strlen_zero(v->value)) {
               ast_string_field_set(user, cid_num, v->value);
               ast_set_flag(user, IAX_HASCALLERID);
            } else {
               ast_string_field_set(user, cid_num, "");
               if (ast_strlen_zero(user->cid_name))
                  ast_clear_flag(user, IAX_HASCALLERID);
            }
         } else if (!strcasecmp(v->name, "accountcode")) {
            ast_string_field_set(user, accountcode, v->value);
         } else if (!strcasecmp(v->name, "mohinterpret")) {
            ast_string_field_set(user, mohinterpret, v->value);
         } else if (!strcasecmp(v->name, "mohsuggest")) {
            ast_string_field_set(user, mohsuggest, v->value);
         } else if (!strcasecmp(v->name, "parkinglot")) {
            ast_string_field_set(user, parkinglot, v->value);
         } else if (!strcasecmp(v->name, "language")) {
            ast_string_field_set(user, language, v->value);
         } else if (!strcasecmp(v->name, "amaflags")) {
            format = ast_cdr_amaflags2int(v->value);
            if (format < 0) {
               ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
            } else {
               user->amaflags = format;
            }
         } else if (!strcasecmp(v->name, "inkeys")) {
            ast_string_field_set(user, inkeys, v->value);
         } else if (!strcasecmp(v->name, "maxauthreq")) {
            user->maxauthreq = atoi(v->value);
            if (user->maxauthreq < 0)
               user->maxauthreq = 0;
         } else if (!strcasecmp(v->name, "adsi")) {
            user->adsi = ast_true(v->value);
         } else if (!strcasecmp(v->name, "requirecalltoken")) {
            /* default is required unless in optional ip list */
            if (ast_false(v->value)) {
               user->calltoken_required = CALLTOKEN_NO;
            } else if (!strcasecmp(v->value, "auto")) {
               user->calltoken_required = CALLTOKEN_AUTO;
            } else if (ast_true(v->value)) {
               user->calltoken_required = CALLTOKEN_YES;
            } else {
               ast_log(LOG_WARNING, "requirecalltoken must be set to a valid value. at line %d\n", v->lineno);
            }
         } /* else if (strcasecmp(v->name,"type")) */
         /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
         v = v->next;
         if (!v) {
            v = alt;
            alt = NULL;
         }
      }
      if (!user->authmethods) {
         if (!ast_strlen_zero(user->secret)) {
            user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
            if (!ast_strlen_zero(user->inkeys))
               user->authmethods |= IAX_AUTH_RSA;
         } else if (!ast_strlen_zero(user->inkeys)) {
            user->authmethods = IAX_AUTH_RSA;
         } else {
            user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
         }
      }
      ast_clear_flag(user, IAX_DELME);
   }
cleanup:
   if (oldha)
      ast_free_ha(oldha);
   if (oldcon)
      free_context(oldcon);
   return user;
}
static int cache_get_callno_locked ( const char *  data) [static]

Definition at line 13054 of file chan_iax2.c.

References add_empty_calltoken_ie(), ARRAY_LEN, ast_debug, AST_FRAME_IAX, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_strdupa, ast_string_field_set, ast_strlen_zero(), iax_ie_data::buf, chan_iax2_pvt::capability, parsed_dial_string::context, create_addr(), parsed_dial_string::exten, find_callno_locked(), IAX_CAPABILITY_FULLBANDWIDTH, IAX_COMMAND_NEW, iax_ie_append_int(), iax_ie_append_short(), iax_ie_append_str(), IAX_IE_CALLED_CONTEXT, IAX_IE_CALLED_NUMBER, IAX_IE_CAPABILITY, IAX_IE_FORMAT, IAX_IE_USERNAME, IAX_IE_VERSION, IAX_PROTO_VERSION, parsed_dial_string::key, LOG_WARNING, NEW_FORCE, parse_dial_string(), parsed_dial_string::password, parsed_dial_string::peer, iax_ie_data::pos, secret, send_command(), create_addr_info::sockfd, and parsed_dial_string::username.

Referenced by find_cache().

{
   struct sockaddr_in sin;
   int x;
   int callno;
   struct iax_ie_data ied;
   struct create_addr_info cai;
   struct parsed_dial_string pds;
   char *tmpstr;

   for (x = 0; x < ARRAY_LEN(iaxs); x++) {
      /* Look for an *exact match* call.  Once a call is negotiated, it can only
         look up entries for a single context */
      if (!ast_mutex_trylock(&iaxsl[x])) {
         if (iaxs[x] && !strcasecmp(data, iaxs[x]->dproot))
            return x;
         ast_mutex_unlock(&iaxsl[x]);
      }
   }

   /* No match found, we need to create a new one */

   memset(&cai, 0, sizeof(cai));
   memset(&ied, 0, sizeof(ied));
   memset(&pds, 0, sizeof(pds));

   tmpstr = ast_strdupa(data);
   parse_dial_string(tmpstr, &pds);

   if (ast_strlen_zero(pds.peer)) {
      ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", data);
      return -1;
   }

   /* Populate our address from the given */
   if (create_addr(pds.peer, NULL, &sin, &cai))
      return -1;

   ast_debug(1, "peer: %s, username: %s, password: %s, context: %s\n",
      pds.peer, pds.username, pds.password, pds.context);

   callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
   if (callno < 1) {
      ast_log(LOG_WARNING, "Unable to create call\n");
      return -1;
   }

   ast_string_field_set(iaxs[callno], dproot, data);
   iaxs[callno]->capability = IAX_CAPABILITY_FULLBANDWIDTH;

   iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
   iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, "TBD");
   /* the string format is slightly different from a standard dial string,
      because the context appears in the 'exten' position
   */
   if (pds.exten)
      iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, pds.exten);
   if (pds.username)
      iax_ie_append_str(&ied, IAX_IE_USERNAME, pds.username);
   iax_ie_append_int(&ied, IAX_IE_FORMAT, IAX_CAPABILITY_FULLBANDWIDTH);
   iax_ie_append_int(&ied, IAX_IE_CAPABILITY, IAX_CAPABILITY_FULLBANDWIDTH);
   /* Keep password handy */
   if (pds.password)
      ast_string_field_set(iaxs[callno], secret, pds.password);
   if (pds.key)
      ast_string_field_set(iaxs[callno], outkey, pds.key);
   /* Start the call going */
   add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
   send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);

   return callno;
}
static unsigned int calc_rxstamp ( struct chan_iax2_pvt p,
unsigned int  offset 
) [static]

Definition at line 5742 of file chan_iax2.c.

References ast_debug, ast_random(), ast_samp2tv(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), chan_iax2_pvt::callno, and chan_iax2_pvt::rxcore.

Referenced by schedule_delivery().

{
   /* Returns where in "receive time" we are.  That is, how many ms
      since we received (or would have received) the frame with timestamp 0 */
   int ms;
#ifdef IAXTESTS
   int jit;
#endif /* IAXTESTS */
   /* Setup rxcore if necessary */
   if (ast_tvzero(p->rxcore)) {
      p->rxcore = ast_tvnow();
      if (iaxdebug)
         ast_debug(1, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
               p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
      p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
#if 1
      if (iaxdebug)
         ast_debug(1, "calc_rxstamp: call=%d: works out as %d.%6.6d\n",
               p->callno, (int)(p->rxcore.tv_sec),(int)( p->rxcore.tv_usec));
#endif
   }

   ms = ast_tvdiff_ms(ast_tvnow(), p->rxcore);
#ifdef IAXTESTS
   if (test_jit) {
      if (!test_jitpct || ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_jitpct)) {
         jit = (int)((float)test_jit * ast_random() / (RAND_MAX + 1.0));
         if ((int)(2.0 * ast_random() / (RAND_MAX + 1.0)))
            jit = -jit;
         ms += jit;
      }
   }
   if (test_late) {
      ms += test_late;
      test_late = 0;
   }
#endif /* IAXTESTS */
   return ms;
}
static unsigned int calc_timestamp ( struct chan_iax2_pvt p,
unsigned int  ts,
struct ast_frame f 
) [static]

Definition at line 5609 of file chan_iax2.c.

References ast_debug, ast_format_rate(), AST_FRAME_CNG, AST_FRAME_IAX, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_samp2tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), chan_iax2_pvt::callno, ast_frame::delivery, ast_frame::frametype, iax2_trunk_peer::lastsent, chan_iax2_pvt::lastsent, MAX_TIMESTAMP_SKEW, chan_iax2_pvt::nextpred, chan_iax2_pvt::notsilenttx, chan_iax2_pvt::offset, chan_iax2_pvt::peercallno, ast_frame::samples, and ast_frame::subclass.

Referenced by iax2_send(), and socket_process().

{
   int ms;
   int voice = 0;
   int genuine = 0;
   int adjust;
   int rate = ast_format_rate(f->subclass) / 1000;
   struct timeval *delivery = NULL;


   /* What sort of frame do we have?: voice is self-explanatory
      "genuine" means an IAX frame - things like LAGRQ/RP, PING/PONG, ACK
      non-genuine frames are CONTROL frames [ringing etc], DTMF
      The "genuine" distinction is needed because genuine frames must get a clock-based timestamp,
      the others need a timestamp slaved to the voice frames so that they go in sequence
   */
   if (f) {
      if (f->frametype == AST_FRAME_VOICE) {
         voice = 1;
         delivery = &f->delivery;
      } else if (f->frametype == AST_FRAME_IAX) {
         genuine = 1;
      } else if (f->frametype == AST_FRAME_CNG) {
         p->notsilenttx = 0;  
      }
   }
   if (ast_tvzero(p->offset)) {
      p->offset = ast_tvnow();
      /* Round to nearest 20ms for nice looking traces */
      p->offset.tv_usec -= p->offset.tv_usec % 20000;
   }
   /* If the timestamp is specified, just send it as is */
   if (ts)
      return ts;
   /* If we have a time that the frame arrived, always use it to make our timestamp */
   if (delivery && !ast_tvzero(*delivery)) {
      ms = ast_tvdiff_ms(*delivery, p->offset);
      if (ms < 0) {
         ms = 0;
      }
      if (iaxdebug)
         ast_debug(3, "calc_timestamp: call %d/%d: Timestamp slaved to delivery time\n", p->callno, iaxs[p->callno]->peercallno);
   } else {
      ms = ast_tvdiff_ms(ast_tvnow(), p->offset);
      if (ms < 0)
         ms = 0;
      if (voice) {
         /* On a voice frame, use predicted values if appropriate */
         if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
            /* Adjust our txcore, keeping voice and non-voice synchronized */
            /* AN EXPLANATION:
               When we send voice, we usually send "calculated" timestamps worked out
               on the basis of the number of samples sent. When we send other frames,
               we usually send timestamps worked out from the real clock.
               The problem is that they can tend to drift out of step because the 
                  source channel's clock and our clock may not be exactly at the same rate.
               We fix this by continuously "tweaking" p->offset.  p->offset is "time zero"
               for this call.  Moving it adjusts timestamps for non-voice frames.
               We make the adjustment in the style of a moving average.  Each time we
               adjust p->offset by 10% of the difference between our clock-derived
               timestamp and the predicted timestamp.  That's why you see "10000"
               below even though IAX2 timestamps are in milliseconds.
               The use of a moving average avoids offset moving too radically.
               Generally, "adjust" roams back and forth around 0, with offset hardly
               changing at all.  But if a consistent different starts to develop it
               will be eliminated over the course of 10 frames (200-300msecs) 
            */
            adjust = (ms - p->nextpred);
            if (adjust < 0)
               p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
            else if (adjust > 0)
               p->offset = ast_tvadd(p->offset, ast_samp2tv(adjust, 10000));

            if (!p->nextpred) {
               p->nextpred = ms; /*f->samples / rate;*/
               if (p->nextpred <= p->lastsent)
                  p->nextpred = p->lastsent + 3;
            }
            ms = p->nextpred;
         } else {
                /* in this case, just use the actual
            * time, since we're either way off
            * (shouldn't happen), or we're  ending a
            * silent period -- and seed the next
            * predicted time.  Also, round ms to the
            * next multiple of frame size (so our
            * silent periods are multiples of
            * frame size too) */

            if (iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
               ast_debug(1, "predicted timestamp skew (%u) > max (%u), using real ts instead.\n",
                  abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);

            if (f->samples >= rate) /* check to make sure we dont core dump */
            {
               int diff = ms % (f->samples / rate);
               if (diff)
                   ms += f->samples/rate - diff;
            }

            p->nextpred = ms;
            p->notsilenttx = 1;
         }
      } else if ( f->frametype == AST_FRAME_VIDEO ) {
         /*
         * IAX2 draft 03 says that timestamps MUST be in order.
         * It does not say anything about several frames having the same timestamp
         * When transporting video, we can have a frame that spans multiple iax packets
         * (so called slices), so it would make sense to use the same timestamp for all of
         * them
         * We do want to make sure that frames don't go backwards though
         */
         if ( (unsigned int)ms < p->lastsent )
            ms = p->lastsent;
      } else {
         /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
            it's a genuine frame */
         if (genuine) {
            /* genuine (IAX LAGRQ etc) must keep their clock-based stamps */
            if (ms <= p->lastsent)
               ms = p->lastsent + 3;
         } else if (abs(ms - p->lastsent) <= MAX_TIMESTAMP_SKEW) {
            /* non-genuine frames (!?) (DTMF, CONTROL) should be pulled into the predicted stream stamps */
            ms = p->lastsent + 3;
         }
      }
   }
   p->lastsent = ms;
   if (voice)
      p->nextpred = p->nextpred + f->samples / rate;
   return ms;
}
static unsigned int calc_txpeerstamp ( struct iax2_trunk_peer tpeer,
int  sampms,
struct timeval *  now 
) [static]

Definition at line 5565 of file chan_iax2.c.

References ast_tvdiff_ms(), ast_tvzero(), iax2_trunk_peer::lastsent, iax2_trunk_peer::lasttxtime, MAX_TIMESTAMP_SKEW, iax2_trunk_peer::trunkact, and iax2_trunk_peer::txtrunktime.

Referenced by send_trunk().

{
   unsigned long int mssincetx; /* unsigned to handle overflows */
   long int ms, pred;

   tpeer->trunkact = *now;
   mssincetx = ast_tvdiff_ms(*now, tpeer->lasttxtime);
   if (mssincetx > 5000 || ast_tvzero(tpeer->txtrunktime)) {
      /* If it's been at least 5 seconds since the last time we transmitted on this trunk, reset our timers */
      tpeer->txtrunktime = *now;
      tpeer->lastsent = 999999;
   }
   /* Update last transmit time now */
   tpeer->lasttxtime = *now;
   
   /* Calculate ms offset */
   ms = ast_tvdiff_ms(*now, tpeer->txtrunktime);
   /* Predict from last value */
   pred = tpeer->lastsent + sampms;
   if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
      ms = pred;
   
   /* We never send the same timestamp twice, so fudge a little if we must */
   if (ms == tpeer->lastsent)
      ms = tpeer->lastsent + 1;
   tpeer->lastsent = ms;
   return ms;
}
static int callno_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 2520 of file chan_iax2.c.

References ast_random().

Referenced by create_callno_pools().

{
   return abs(ast_random());
}
static int calltoken_required ( struct sockaddr_in *  sin,
const char *  name,
int  subclass 
) [static]

Definition at line 2068 of file chan_iax2.c.

References addr_range_match_address_cb(), ao2_callback, ao2_ref, ast_debug, ast_inet_ntoa(), CALLTOKEN_AUTO, CALLTOKEN_DEFAULT, CALLTOKEN_NO, iax2_peer::calltoken_required, iax2_user::calltoken_required, find_peer(), find_user(), IAX_COMMAND_NEW, peer_unref(), realtime_peer(), realtime_user(), S_OR, and user_unref().

Referenced by handle_call_token().

{
   struct addr_range *addr_range;
   struct iax2_peer *peer = NULL;
   struct iax2_user *user = NULL;
   /* if no username is given, check for guest accounts */
   const char *find = S_OR(name, "guest");
   int res = 1;  /* required by default */
   int optional = 0;
   enum calltoken_peer_enum calltoken_required = CALLTOKEN_DEFAULT;
   /* There are only two cases in which calltoken validation is not required.
    * Case 1. sin falls within the list of address ranges specified in the calltoken optional table and
    *         the peer definition has not set the requirecalltoken option.
    * Case 2. Username is a valid peer/user, and that peer has requirecalltoken set either auto or no.
    */

   /* ----- Case 1 ----- */
   if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, sin))) {
      ao2_ref(addr_range, -1);
      optional = 1;
   }

   /* ----- Case 2 ----- */
   if ((subclass == IAX_COMMAND_NEW) && (user = find_user(find))) {
      calltoken_required = user->calltoken_required;
   } else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, sin))) {
      calltoken_required = user->calltoken_required;
   } else if ((subclass != IAX_COMMAND_NEW) && (peer = find_peer(find, 0))) {
      calltoken_required = peer->calltoken_required;
   } else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, sin))) {
      calltoken_required = peer->calltoken_required;
   }

   if (peer) {
      peer_unref(peer);
   }
   if (user) {
      user_unref(user);
   }

   ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %d \n", ast_inet_ntoa(sin->sin_addr), name, optional, calltoken_required);
   if (((calltoken_required == CALLTOKEN_NO) || (calltoken_required == CALLTOKEN_AUTO)) ||
      (optional && (calltoken_required == CALLTOKEN_DEFAULT))) {
      res = 0;
   }

   return res;
}
static int check_access ( int  callno,
struct sockaddr_in *  sin,
struct iax_ies ies 
) [static]

Definition at line 7231 of file chan_iax2.c.

References iax2_user::accountcode, iax2_user::adsi, chan_iax2_pvt::adsi, iax_ies::adsicpe, chan_iax2_pvt::amaflags, iax2_user::amaflags, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, apply_context(), ast_apply_ha(), ast_codec_pref_convert(), ast_copy_flags, ast_db_get(), ast_inet_ntoa(), ast_log(), AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, AST_PRES_NUMBER_NOT_AVAILABLE, ast_set2_flag, ast_set_flag, ast_shrink_phone_number(), ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_variable_new(), iax2_user::authmethods, chan_iax2_pvt::authmethods, chan_iax2_pvt::authrej, iax_ies::called_context, iax_ies::called_number, iax_ies::calling_ani, iax_ies::calling_name, iax_ies::calling_number, chan_iax2_pvt::calling_pres, iax_ies::calling_pres, chan_iax2_pvt::calling_tns, iax_ies::calling_tns, chan_iax2_pvt::calling_ton, iax_ies::calling_ton, iax2_user::capability, chan_iax2_pvt::capability, iax_ies::capability, iax2_user::cid_name, cid_name, iax2_user::cid_num, cid_num, iax_ies::codec_prefs, iax2_context::context, chan_iax2_pvt::context, context, iax2_user::contexts, iax2_user::dbsecret, DEFAULT_CONTEXT, iax_ies::dnid, iax2_user::encmethods, chan_iax2_pvt::encmethods, exten, ast_variable::file, iax_ies::format, iax2_user::ha, iax2_getpeertrunk(), IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_CODEC_NOCAP, IAX_CODEC_NOPREFS, IAX_CODEC_USER_FIRST, IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_HASCALLERID, IAX_IMMEDIATE, IAX_MAXAUTHREQ, IAX_NOTRANSFER, IAX_PROTO_VERSION, IAX_SHRINKCALLERID, IAX_TRANSFERMEDIA, IAX_TRUNK, IAX_USEJITTERBUF, iax2_user::inkeys, iax2_user::language, iax_ies::language, LOG_WARNING, iax2_user::maxauthreq, iax2_user::mohinterpret, iax2_user::mohsuggest, ast_variable::name, iax2_user::name, ast_variable::next, parkinglot, iax2_user::parkinglot, chan_iax2_pvt::peeradsicpe, chan_iax2_pvt::peercapability, chan_iax2_pvt::peerformat, iax2_user::prefs, chan_iax2_pvt::prefs, prefs, iax_ies::rdnis, realtime_user(), secret, iax2_user::secret, user, user_unref(), iax_ies::username, ast_variable::value, chan_iax2_pvt::vars, iax2_user::vars, iax_ies::version, and version.

Referenced by socket_process().

{
   /* Start pessimistic */
   int res = -1;
   int version = 2;
   struct iax2_user *user = NULL, *best = NULL;
   int bestscore = 0;
   int gotcapability = 0;
   struct ast_variable *v = NULL, *tmpvar = NULL;
   struct ao2_iterator i;

   if (!iaxs[callno])
      return res;
   if (ies->called_number)
      ast_string_field_set(iaxs[callno], exten, ies->called_number);
   if (ies->calling_number) {
      if (ast_test_flag(&globalflags, IAX_SHRINKCALLERID)) { 
         ast_shrink_phone_number(ies->calling_number);
      }
      ast_string_field_set(iaxs[callno], cid_num, ies->calling_number);
   }
   if (ies->calling_name)
      ast_string_field_set(iaxs[callno], cid_name, ies->calling_name);
   if (ies->calling_ani)
      ast_string_field_set(iaxs[callno], ani, ies->calling_ani);
   if (ies->dnid)
      ast_string_field_set(iaxs[callno], dnid, ies->dnid);
   if (ies->rdnis)
      ast_string_field_set(iaxs[callno], rdnis, ies->rdnis);
   if (ies->called_context)
      ast_string_field_set(iaxs[callno], context, ies->called_context);
   if (ies->language)
      ast_string_field_set(iaxs[callno], language, ies->language);
   if (ies->username)
      ast_string_field_set(iaxs[callno], username, ies->username);
   if (ies->calling_ton > -1)
      iaxs[callno]->calling_ton = ies->calling_ton;
   if (ies->calling_tns > -1)
      iaxs[callno]->calling_tns = ies->calling_tns;
   if (ies->calling_pres > -1)
      iaxs[callno]->calling_pres = ies->calling_pres;
   if (ies->format)
      iaxs[callno]->peerformat = ies->format;
   if (ies->adsicpe)
      iaxs[callno]->peeradsicpe = ies->adsicpe;
   if (ies->capability) {
      gotcapability = 1;
      iaxs[callno]->peercapability = ies->capability;
   } 
   if (ies->version)
      version = ies->version;

   /* Use provided preferences until told otherwise for actual preferences */
   if(ies->codec_prefs) {
      ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
      ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
   }

   if (!gotcapability) 
      iaxs[callno]->peercapability = iaxs[callno]->peerformat;
   if (version > IAX_PROTO_VERSION) {
      ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n", 
         ast_inet_ntoa(sin->sin_addr), version);
      return res;
   }
   /* Search the userlist for a compatible entry, and fill in the rest */
   i = ao2_iterator_init(users, 0);
   while ((user = ao2_iterator_next(&i))) {
      if ((ast_strlen_zero(iaxs[callno]->username) ||          /* No username specified */
         !strcmp(iaxs[callno]->username, user->name)) /* Or this username specified */
         && ast_apply_ha(user->ha, sin)   /* Access is permitted from this IP */
         && (ast_strlen_zero(iaxs[callno]->context) ||         /* No context specified */
              apply_context(user->contexts, iaxs[callno]->context))) {        /* Context is permitted */
         if (!ast_strlen_zero(iaxs[callno]->username)) {
            /* Exact match, stop right now. */
            if (best)
               user_unref(best);
            best = user;
            break;
         } else if (ast_strlen_zero(user->secret) && ast_strlen_zero(user->dbsecret) && ast_strlen_zero(user->inkeys)) {
            /* No required authentication */
            if (user->ha) {
               /* There was host authentication and we passed, bonus! */
               if (bestscore < 4) {
                  bestscore = 4;
                  if (best)
                     user_unref(best);
                  best = user;
                  continue;
               }
            } else {
               /* No host access, but no secret, either, not bad */
               if (bestscore < 3) {
                  bestscore = 3;
                  if (best)
                     user_unref(best);
                  best = user;
                  continue;
               }
            }
         } else {
            if (user->ha) {
               /* Authentication, but host access too, eh, it's something.. */
               if (bestscore < 2) {
                  bestscore = 2;
                  if (best)
                     user_unref(best);
                  best = user;
                  continue;
               }
            } else {
               /* Authentication and no host access...  This is our baseline */
               if (bestscore < 1) {
                  bestscore = 1;
                  if (best)
                     user_unref(best);
                  best = user;
                  continue;
               }
            }
         }
      }
      user_unref(user);
   }
   ao2_iterator_destroy(&i);
   user = best;
   if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
      user = realtime_user(iaxs[callno]->username, sin);
      if (user && !ast_strlen_zero(iaxs[callno]->context) &&         /* No context specified */
          !apply_context(user->contexts, iaxs[callno]->context)) {      /* Context is permitted */
         user = user_unref(user);
      }
   }
   if (user) {
      /* We found our match (use the first) */
      /* copy vars */
      for (v = user->vars ; v ; v = v->next) {
         if((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
            tmpvar->next = iaxs[callno]->vars; 
            iaxs[callno]->vars = tmpvar;
         }
      }
      /* If a max AUTHREQ restriction is in place, activate it */
      if (user->maxauthreq > 0)
         ast_set_flag(iaxs[callno], IAX_MAXAUTHREQ);
      iaxs[callno]->prefs = user->prefs;
      ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST | IAX_IMMEDIATE | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT);
      iaxs[callno]->encmethods = user->encmethods;
      /* Store the requested username if not specified */
      if (ast_strlen_zero(iaxs[callno]->username))
         ast_string_field_set(iaxs[callno], username, user->name);
      /* Store whether this is a trunked call, too, of course, and move if appropriate */
      ast_copy_flags(iaxs[callno], user, IAX_TRUNK);
      iaxs[callno]->capability = user->capability;
      /* And use the default context */
      if (ast_strlen_zero(iaxs[callno]->context)) {
         if (user->contexts)
            ast_string_field_set(iaxs[callno], context, user->contexts->context);
         else
            ast_string_field_set(iaxs[callno], context, DEFAULT_CONTEXT);
      }
      /* And any input keys */
      ast_string_field_set(iaxs[callno], inkeys, user->inkeys);
      /* And the permitted authentication methods */
      iaxs[callno]->authmethods = user->authmethods;
      iaxs[callno]->adsi = user->adsi;
      /* If the user has callerid, override the remote caller id. */
      if (ast_test_flag(user, IAX_HASCALLERID)) {
         iaxs[callno]->calling_tns = 0;
         iaxs[callno]->calling_ton = 0;
         ast_string_field_set(iaxs[callno], cid_num, user->cid_num);
         ast_string_field_set(iaxs[callno], cid_name, user->cid_name);
         ast_string_field_set(iaxs[callno], ani, user->cid_num);
         iaxs[callno]->calling_pres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
      } else if (ast_strlen_zero(iaxs[callno]->cid_num) && ast_strlen_zero(iaxs[callno]->cid_name)) {
         iaxs[callno]->calling_pres = AST_PRES_NUMBER_NOT_AVAILABLE;
      } /* else user is allowed to set their own CID settings */
      if (!ast_strlen_zero(user->accountcode))
         ast_string_field_set(iaxs[callno], accountcode, user->accountcode);
      if (!ast_strlen_zero(user->mohinterpret))
         ast_string_field_set(iaxs[callno], mohinterpret, user->mohinterpret);
      if (!ast_strlen_zero(user->mohsuggest))
         ast_string_field_set(iaxs[callno], mohsuggest, user->mohsuggest);
      if (!ast_strlen_zero(user->parkinglot))
         ast_string_field_set(iaxs[callno], parkinglot, user->parkinglot);
      if (user->amaflags)
         iaxs[callno]->amaflags = user->amaflags;
      if (!ast_strlen_zero(user->language))
         ast_string_field_set(iaxs[callno], language, user->language);
      ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);   
      /* Keep this check last */
      if (!ast_strlen_zero(user->dbsecret)) {
         char *family, *key=NULL;
         char buf[80];
         family = ast_strdupa(user->dbsecret);
         key = strchr(family, '/');
         if (key) {
            *key = '\0';
            key++;
         }
         if (!key || ast_db_get(family, key, buf, sizeof(buf)))
            ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", user->dbsecret);
         else
            ast_string_field_set(iaxs[callno], secret, buf);
      } else
         ast_string_field_set(iaxs[callno], secret, user->secret);
      res = 0;
      user = user_unref(user);
   } else {
       /* user was not found, but we should still fake an AUTHREQ.
        * Set authmethods to the last known authmethod used by the system
        * Set a fake secret, it's not looked at, just required to attempt authentication.
        * Set authrej so the AUTHREP is rejected without even looking at its contents */
      iaxs[callno]->authmethods = last_authmethod ? last_authmethod : (IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT);
      ast_string_field_set(iaxs[callno], secret, "badsecret");
      iaxs[callno]->authrej = 1;
      if (!ast_strlen_zero(iaxs[callno]->username)) {
         /* only send the AUTHREQ if a username was specified. */
         res = 0;
      }
   }
   ast_set2_flag(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);  
   return res;
}
static int check_provisioning ( struct sockaddr_in *  sin,
int  sockfd,
char *  si,
unsigned int  ver 
) [static]

Definition at line 9028 of file chan_iax2.c.

References ast_debug, iax2_provision(), and iax_provision_version().

Referenced by socket_process().

{
   unsigned int ourver;
   char rsi[80];
   snprintf(rsi, sizeof(rsi), "si-%s", si);
   if (iax_provision_version(&ourver, rsi, 1))
      return 0;
   ast_debug(1, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
   if (ourver != ver) 
      iax2_provision(sin, sockfd, NULL, rsi, 1);
   return 0;
}
static int check_srcaddr ( struct sockaddr *  sa,
socklen_t  salen 
) [static]

Check if address can be used as packet source.

Returns:
0 address available, 1 address unavailable, -1 error

Definition at line 11811 of file chan_iax2.c.

References ast_debug, ast_log(), errno, and LOG_ERROR.

Referenced by peer_set_srcaddr().

{
   int sd;
   int res;
   
   sd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sd < 0) {
      ast_log(LOG_ERROR, "Socket: %s\n", strerror(errno));
      return -1;
   }

   res = bind(sd, sa, salen);
   if (res < 0) {
      ast_debug(1, "Can't bind: %s\n", strerror(errno));
      close(sd);
      return 1;
   }

   close(sd);
   return 0;
}
static void cleanup_thread_list ( void *  head) [static]

Definition at line 13664 of file chan_iax2.c.

References AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, iax2_thread::cond, iax2_thread::lock, signal_condition(), iax2_thread::stop, thread, and iax2_thread::threadid.

Referenced by __unload_module().

{
   AST_LIST_HEAD(iax2_thread_list, iax2_thread);
   struct iax2_thread_list *list_head = head;
   struct iax2_thread *thread;

   AST_LIST_LOCK(list_head);
   while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, list))) {
      pthread_t thread_id = thread->threadid;

      thread->stop = 1;
      signal_condition(&thread->lock, &thread->cond);

      AST_LIST_UNLOCK(list_head);
      pthread_join(thread_id, NULL);
      AST_LIST_LOCK(list_head);
   }
   AST_LIST_UNLOCK(list_head);
}
static int complete_dpreply ( struct chan_iax2_pvt pvt,
struct iax_ies ies 
) [static]

Definition at line 8013 of file chan_iax2.c.

References ARRAY_LEN, ast_copy_string(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, CACHE_FLAG_CANEXIST, CACHE_FLAG_EXISTS, CACHE_FLAG_MATCHMORE, CACHE_FLAG_NONEXISTENT, CACHE_FLAG_PENDING, CACHE_FLAG_UNKNOWN, iax_ies::called_number, iax2_dpcache::callno, iax_ies::dpstatus, iax2_dpcache::expiry, iax2_dpcache::exten, exten, iax2_dpcache::flags, IAX_DPSTATUS_CANEXIST, IAX_DPSTATUS_EXISTS, IAX_DPSTATUS_MATCHMORE, IAX_DPSTATUS_NONEXISTENT, iaxdefaultdpcache, matchmore(), iax2_dpcache::orig, iax2_dpcache::peer_list, iax_ies::refresh, status, and iax2_dpcache::waiters.

Referenced by socket_process().

{
   char exten[256] = "";
   int status = CACHE_FLAG_UNKNOWN, expiry = iaxdefaultdpcache, x, matchmore = 0;
   struct iax2_dpcache *dp = NULL;
   
   if (ies->called_number)
      ast_copy_string(exten, ies->called_number, sizeof(exten));
   
   if (ies->dpstatus & IAX_DPSTATUS_EXISTS)
      status = CACHE_FLAG_EXISTS;
   else if (ies->dpstatus & IAX_DPSTATUS_CANEXIST)
      status = CACHE_FLAG_CANEXIST;
   else if (ies->dpstatus & IAX_DPSTATUS_NONEXISTENT)
      status = CACHE_FLAG_NONEXISTENT;

   if (ies->refresh)
      expiry = ies->refresh;
   if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
      matchmore = CACHE_FLAG_MATCHMORE;
   
   AST_LIST_LOCK(&dpcache);
   AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, peer_list) {
      if (strcmp(dp->exten, exten))
         continue;
      AST_LIST_REMOVE_CURRENT(peer_list);
      dp->callno = 0;
      dp->expiry.tv_sec = dp->orig.tv_sec + expiry;
      if (dp->flags & CACHE_FLAG_PENDING) {
         dp->flags &= ~CACHE_FLAG_PENDING;
         dp->flags |= status;
         dp->flags |= matchmore;
      }
      /* Wake up waiters */
      for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
         if (dp->waiters[x] > -1) {
            if (write(dp->waiters[x], "asdf", 4) < 0) {
            }
         }
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;
   AST_LIST_UNLOCK(&dpcache);

   return 0;
}
static char * complete_iax2_peers ( const char *  line,
const char *  word,
int  pos,
int  state,
int  flags 
) [static]

Definition at line 3669 of file chan_iax2.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_strdup, ast_test_flag, iax2_peer::name, and peer_unref().

Referenced by handle_cli_iax2_prune_realtime(), handle_cli_iax2_set_debug(), and handle_cli_iax2_show_peer().

{
   int which = 0;
   struct iax2_peer *peer;
   char *res = NULL;
   int wordlen = strlen(word);
   struct ao2_iterator i;

   i = ao2_iterator_init(peers, 0);
   while ((peer = ao2_iterator_next(&i))) {
      if (!strncasecmp(peer->name, word, wordlen) && ++which > state
         && (!flags || ast_test_flag(peer, flags))) {
         res = ast_strdup(peer->name);
         peer_unref(peer);
         break;
      }
      peer_unref(peer);
   }
   ao2_iterator_destroy(&i);

   return res;
}
static char * complete_iax2_unregister ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 6599 of file chan_iax2.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_strdup, iax2_peer::expire, iax2_peer::name, and peer_unref().

Referenced by handle_cli_iax2_unregister().

{
   int which = 0;
   struct iax2_peer *p = NULL;
   char *res = NULL;
   int wordlen = strlen(word);

   /* 0 - iax2; 1 - unregister; 2 - <peername> */
   if (pos == 2) {
      struct ao2_iterator i = ao2_iterator_init(peers, 0);
      while ((p = ao2_iterator_next(&i))) {
         if (!strncasecmp(p->name, word, wordlen) && 
            ++which > state && p->expire > 0) {
            res = ast_strdup(p->name);
            peer_unref(p);
            break;
         }
         peer_unref(p);
      }
      ao2_iterator_destroy(&i);
   }

   return res;
}
static int complete_transfer ( int  callno,
struct iax_ies ies 
) [static]

Definition at line 8060 of file chan_iax2.c.

References chan_iax2_pvt::addr, chan_iax2_pvt::aseqno, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), iax_frame::callno, iax_ies::callno, chan_iax2_pvt::callno, jb_frame::data, DEFAULT_RETRY_TIME, iax2_frame_free(), chan_iax2_pvt::iseqno, chan_iax2_pvt::jb, jb_getall(), JB_OK, jb_reset(), chan_iax2_pvt::lag, chan_iax2_pvt::last, chan_iax2_pvt::lastsent, LOG_WARNING, chan_iax2_pvt::nextpred, chan_iax2_pvt::offset, chan_iax2_pvt::oseqno, chan_iax2_pvt::peercallno, peercnt_add(), peercnt_remove_by_addr(), chan_iax2_pvt::pingtime, remove_by_peercallno(), remove_by_transfercallno(), iax_frame::retries, chan_iax2_pvt::rseqno, chan_iax2_pvt::rxcore, store_by_peercallno(), chan_iax2_pvt::svideoformat, chan_iax2_pvt::svoiceformat, chan_iax2_pvt::transfer, TRANSFER_NONE, chan_iax2_pvt::transfercallno, chan_iax2_pvt::transferring, chan_iax2_pvt::videoformat, and chan_iax2_pvt::voiceformat.

Referenced by socket_process().

{
   int peercallno = 0;
   struct chan_iax2_pvt *pvt = iaxs[callno];
   struct iax_frame *cur;
   jb_frame frame;

   if (ies->callno)
      peercallno = ies->callno;

   if (peercallno < 1) {
      ast_log(LOG_WARNING, "Invalid transfer request\n");
      return -1;
   }
   remove_by_transfercallno(pvt);
   /* since a transfer has taken place, the address will change.
    * This must be accounted for in the peercnts table.  Remove
    * the old address and add the new one */
   peercnt_remove_by_addr(&pvt->addr);
   peercnt_add(&pvt->transfer);
   /* now copy over the new address */
   memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
   memset(&pvt->transfer, 0, sizeof(pvt->transfer));
   /* Reset sequence numbers */
   pvt->oseqno = 0;
   pvt->rseqno = 0;
   pvt->iseqno = 0;
   pvt->aseqno = 0;

   if (pvt->peercallno) {
      remove_by_peercallno(pvt);
   }
   pvt->peercallno = peercallno;
   /*this is where the transfering call swiches hash tables */
   store_by_peercallno(pvt);
   pvt->transferring = TRANSFER_NONE;
   pvt->svoiceformat = -1;
   pvt->voiceformat = 0;
   pvt->svideoformat = -1;
   pvt->videoformat = 0;
   pvt->transfercallno = 0;
   memset(&pvt->rxcore, 0, sizeof(pvt->rxcore));
   memset(&pvt->offset, 0, sizeof(pvt->offset));
   /* reset jitterbuffer */
   while(jb_getall(pvt->jb,&frame) == JB_OK)
      iax2_frame_free(frame.data);
   jb_reset(pvt->jb);
   pvt->lag = 0;
   pvt->last = 0;
   pvt->lastsent = 0;
   pvt->nextpred = 0;
   pvt->pingtime = DEFAULT_RETRY_TIME;
   AST_LIST_LOCK(&frame_queue);
   AST_LIST_TRAVERSE(&frame_queue, cur, list) {
      /* We must cancel any packets that would have been transmitted
         because now we're talking to someone new.  It's okay, they
         were transmitted to someone that didn't care anyway. */
      if (callno == cur->callno) 
         cur->retries = -1;
   }
   AST_LIST_UNLOCK(&frame_queue);
   return 0; 
}
static unsigned char compress_subclass ( int  subclass) [static]

Definition at line 1501 of file chan_iax2.c.

References ast_log(), IAX_FLAG_SC_LOG, IAX_MAX_SHIFT, and LOG_WARNING.

Referenced by iax2_send(), raw_hangup(), and send_apathetic_reply().

{
   int x;
   int power=-1;
   /* If it's 128 or smaller, just return it */
   if (subclass < IAX_FLAG_SC_LOG)
      return subclass;
   /* Otherwise find its power */
   for (x = 0; x < IAX_MAX_SHIFT; x++) {
      if (subclass & (1 << x)) {
         if (power > -1) {
            ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);
            return 0;
         } else
            power = x;
      }
   }
   return power | IAX_FLAG_SC_LOG;
}
static int create_addr ( const char *  peername,
struct ast_channel c,
struct sockaddr_in *  sin,
struct create_addr_info cai 
) [static]

Definition at line 4370 of file chan_iax2.c.

References iax2_peer::addr, iax2_peer::adsi, create_addr_info::adsi, ast_clear_flag, ast_codec_pref_convert(), ast_codec_pref_prepend(), ast_copy_flags, ast_copy_string(), ast_db_get(), ast_debug, ast_get_ip_or_srv(), ast_log(), ast_strdupa, ast_strlen_zero(), iax2_peer::capability, create_addr_info::capability, iax2_peer::context, create_addr_info::context, iax2_peer::dbsecret, iax2_peer::defaddr, defaultsockfd, iax2_peer::encmethods, create_addr_info::encmethods, find_peer(), create_addr_info::found, IAX_DEFAULT_PORTNO, IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_NOTRANSFER, IAX_SENDANI, IAX_TRANSFERMEDIA, IAX_TRUNK, IAX_USEJITTERBUF, iax2_peer::lastms, LOG_WARNING, iax2_peer::maxms, create_addr_info::maxtime, iax2_peer::mohinterpret, create_addr_info::mohinterpret, iax2_peer::mohsuggest, create_addr_info::mohsuggest, ast_channel::nativeformats, iax2_peer::outkey, create_addr_info::outkey, peer_unref(), iax2_peer::peercontext, create_addr_info::peercontext, iax2_peer::prefs, create_addr_info::prefs, prefs, iax2_peer::secret, create_addr_info::secret, iax2_peer::sockfd, create_addr_info::sockfd, create_addr_info::timezone, iax2_peer::username, create_addr_info::username, and iax2_peer::zonetag.

Referenced by cache_get_callno_locked(), iax2_call(), iax2_provision(), and iax2_request().

{
   struct iax2_peer *peer;
   int res = -1;
   struct ast_codec_pref ourprefs;

   ast_clear_flag(cai, IAX_SENDANI | IAX_TRUNK);
   cai->sockfd = defaultsockfd;
   cai->maxtime = 0;
   sin->sin_family = AF_INET;

   if (!(peer = find_peer(peername, 1))) {
      cai->found = 0;
      if (ast_get_ip_or_srv(sin, peername, srvlookup ? "_iax._udp" : NULL)) {
         ast_log(LOG_WARNING, "No such host: %s\n", peername);
         return -1;
      }
      sin->sin_port = htons(IAX_DEFAULT_PORTNO);
      /* use global iax prefs for unknown peer/user */
      /* But move the calling channel's native codec to the top of the preference list */
      memcpy(&ourprefs, &prefs, sizeof(ourprefs));
      if (c)
         ast_codec_pref_prepend(&ourprefs, c->nativeformats, 1);
      ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
      return 0;
   }

   cai->found = 1;
   
   /* if the peer has no address (current or default), return failure */
   if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr))
      goto return_unref;

   /* if the peer is being monitored and is currently unreachable, return failure */
   if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
      goto return_unref;

   ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
   cai->maxtime = peer->maxms;
   cai->capability = peer->capability;
   cai->encmethods = peer->encmethods;
   cai->sockfd = peer->sockfd;
   cai->adsi = peer->adsi;
   memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
   /* Move the calling channel's native codec to the top of the preference list */
   if (c) {
      ast_debug(1, "prepending %x to prefs\n", c->nativeformats);
      ast_codec_pref_prepend(&ourprefs, c->nativeformats, 1);
   }
   ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
   ast_copy_string(cai->context, peer->context, sizeof(cai->context));
   ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
   ast_copy_string(cai->username, peer->username, sizeof(cai->username));
   ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone));
   ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey));
   ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret));
   ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest));
   if (ast_strlen_zero(peer->dbsecret)) {
      ast_copy_string(cai->secret, peer->secret, sizeof(cai->secret));
   } else {
      char *family;
      char *key = NULL;

      family = ast_strdupa(peer->dbsecret);
      key = strchr(family, '/');
      if (key)
         *key++ = '\0';
      if (!key || ast_db_get(family, key, cai->secret, sizeof(cai->secret))) {
         ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", peer->dbsecret);
         goto return_unref;
      }
   }

   if (peer->addr.sin_addr.s_addr) {
      sin->sin_addr = peer->addr.sin_addr;
      sin->sin_port = peer->addr.sin_port;
   } else {
      sin->sin_addr = peer->defaddr.sin_addr;
      sin->sin_port = peer->defaddr.sin_port;
   }

   res = 0;

return_unref:
   peer_unref(peer);

   return res;
}
static int create_callno_pools ( void  ) [static]

Definition at line 2525 of file chan_iax2.c.

References ao2_alloc, ao2_container_alloc, ao2_link, ao2_ref, callno_entry::callno, callno_hash(), IAX_MAX_CALLS, and TRUNK_CALL_START.

Referenced by load_objects().

{
   uint16_t i;

   if (!(callno_pool = ao2_container_alloc(CALLNO_POOL_BUCKETS, callno_hash, NULL))) {
      return -1;
   }

   if (!(callno_pool_trunk = ao2_container_alloc(CALLNO_POOL_BUCKETS, callno_hash, NULL))) {
      return -1;
   }

   /* start at 2, 0 and 1 are reserved */
   for (i = 2; i <= IAX_MAX_CALLS; i++) {
      struct callno_entry *callno_entry;

      if (!(callno_entry = ao2_alloc(sizeof(*callno_entry), NULL))) {
         return -1;
      }

      callno_entry->callno = i;

      if (i < TRUNK_CALL_START) {
         ao2_link(callno_pool, callno_entry);
      } else {
         ao2_link(callno_pool_trunk, callno_entry);
      }

      ao2_ref(callno_entry, -1);
   }

   return 0;
}
static int decode_frame ( ast_aes_decrypt_key dcx,
struct ast_iax2_full_hdr fh,
struct ast_frame f,
int *  datalen 
) [static]

Definition at line 5964 of file chan_iax2.c.

References ast_debug, AST_FRAME_VIDEO, ast_iax2_full_hdr::csub, ast_iax2_mini_enc_hdr::encdata, ast_iax2_full_enc_hdr::encdata, ast_frame::frametype, IAX_FLAG_FULL, memcpy_decrypt(), ast_iax2_full_hdr::scallno, ast_frame::subclass, ast_iax2_full_hdr::type, and uncompress_subclass().

Referenced by decrypt_frame(), and update_packet().

{
   int padding;
   unsigned char *workspace;

   workspace = alloca(*datalen);
   memset(f, 0, sizeof(*f));
   if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
      struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
      if (*datalen < 16 + sizeof(struct ast_iax2_full_hdr))
         return -1;
      /* Decrypt */
      memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr), dcx);

      padding = 16 + (workspace[15] & 0x0f);
      if (iaxdebug)
         ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, workspace[15]);
      if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
         return -1;

      *datalen -= padding;
      memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
      f->frametype = fh->type;
      if (f->frametype == AST_FRAME_VIDEO) {
         f->subclass = uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1);
      } else {
         f->subclass = uncompress_subclass(fh->csub);
      }
   } else {
      struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
      if (iaxdebug)
         ast_debug(1, "Decoding mini with length %d\n", *datalen);
      if (*datalen < 16 + sizeof(struct ast_iax2_mini_hdr))
         return -1;
      /* Decrypt */
      memcpy_decrypt(workspace, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), dcx);
      padding = 16 + (workspace[15] & 0x0f);
      if (*datalen < padding + sizeof(struct ast_iax2_mini_hdr))
         return -1;
      *datalen -= padding;
      memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
   }
   return 0;
}
static int decrypt_frame ( int  callno,
struct ast_iax2_full_hdr fh,
struct ast_frame f,
int *  datalen 
) [static]

Definition at line 6050 of file chan_iax2.c.

References ast_set_flag, ast_strdupa, ast_test_flag, build_encryption_keys(), decode_frame(), IAX_KEYPOPULATED, MD5Final(), MD5Init(), MD5Update(), secret, and strsep().

Referenced by socket_process().

{
   int res=-1;
   if (!ast_test_flag(iaxs[callno], IAX_KEYPOPULATED)) {
      /* Search for possible keys, given secrets */
      struct MD5Context md5;
      unsigned char digest[16];
      char *tmppw, *stringp;
      
      tmppw = ast_strdupa(iaxs[callno]->secret);
      stringp = tmppw;
      while ((tmppw = strsep(&stringp, ";"))) {
         MD5Init(&md5);
         MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
         MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
         MD5Final(digest, &md5);
         build_encryption_keys(digest, iaxs[callno]);
         res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
         if (!res) {
            ast_set_flag(iaxs[callno], IAX_KEYPOPULATED);
            break;
         }
      }
   } else 
      res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
   return res;
}
static void defer_full_frame ( struct iax2_thread from_here,
struct iax2_thread to_here 
) [static]

Queue the last read full frame for processing by a certain thread.

If there are already any full frames queued, they are sorted by sequence number.

Definition at line 9188 of file chan_iax2.c.

References ast_calloc, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), iax2_thread::buf, iax2_pkt_buf::buf, iax2_thread::buf_len, iax2_thread::full_frames, iax2_pkt_buf::len, iax2_thread::lock, and ast_iax2_full_hdr::oseqno.

Referenced by socket_read().

{
   struct iax2_pkt_buf *pkt_buf, *cur_pkt_buf;
   struct ast_iax2_full_hdr *fh, *cur_fh;

   if (!(pkt_buf = ast_calloc(1, sizeof(*pkt_buf) + from_here->buf_len)))
      return;

   pkt_buf->len = from_here->buf_len;
   memcpy(pkt_buf->buf, from_here->buf, pkt_buf->len);

   fh = (struct ast_iax2_full_hdr *) pkt_buf->buf;
   ast_mutex_lock(&to_here->lock);
   AST_LIST_TRAVERSE_SAFE_BEGIN(&to_here->full_frames, cur_pkt_buf, entry) {
      cur_fh = (struct ast_iax2_full_hdr *) cur_pkt_buf->buf;
      if (fh->oseqno < cur_fh->oseqno) {
         AST_LIST_INSERT_BEFORE_CURRENT(pkt_buf, entry);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END

   if (!cur_pkt_buf)
      AST_LIST_INSERT_TAIL(&to_here->full_frames, pkt_buf, entry);
   
   ast_mutex_unlock(&to_here->lock);
}
static void destroy_firmware ( struct iax_firmware cur) [static]

Definition at line 2856 of file chan_iax2.c.

References ast_free, ast_iax2_firmware_header::datalen, iax_firmware::fd, and iax_firmware::fwh.

Referenced by reload_firmware().

{
   /* Close firmware */
   if (cur->fwh) {
      munmap((void*)cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
   }
   close(cur->fd);
   ast_free(cur);
}
static void dp_lookup ( int  callno,
const char *  context,
const char *  callednum,
const char *  callerid,
int  skiplock 
) [static]

Definition at line 8889 of file chan_iax2.c.

References ast_canmatch_extension(), ast_exists_extension(), AST_FRAME_IAX, ast_ignore_pattern(), ast_matchmore_extension(), ast_mutex_lock(), ast_mutex_unlock(), ast_parking_ext(), iax_ie_data::buf, IAX_COMMAND_DPREP, IAX_DPSTATUS_CANEXIST, IAX_DPSTATUS_EXISTS, IAX_DPSTATUS_IGNOREPAT, IAX_DPSTATUS_MATCHMORE, IAX_DPSTATUS_NONEXISTENT, iax_ie_append_short(), iax_ie_append_str(), IAX_IE_CALLED_NUMBER, IAX_IE_DPSTATUS, IAX_IE_REFRESH, iax_ie_data::pos, and send_command().

Referenced by dp_lookup_thread(), and socket_process().

{
   unsigned short dpstatus = 0;
   struct iax_ie_data ied1;
   int mm;

   memset(&ied1, 0, sizeof(ied1));
   mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
   /* Must be started */
   if (!strcmp(callednum, ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
      dpstatus = IAX_DPSTATUS_EXISTS;
   } else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
      dpstatus = IAX_DPSTATUS_CANEXIST;
   } else {
      dpstatus = IAX_DPSTATUS_NONEXISTENT;
   }
   if (ast_ignore_pattern(context, callednum))
      dpstatus |= IAX_DPSTATUS_IGNOREPAT;
   if (mm)
      dpstatus |= IAX_DPSTATUS_MATCHMORE;
   if (!skiplock)
      ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      iax_ie_append_str(&ied1, IAX_IE_CALLED_NUMBER, callednum);
      iax_ie_append_short(&ied1, IAX_IE_DPSTATUS, dpstatus);
      iax_ie_append_short(&ied1, IAX_IE_REFRESH, iaxdefaultdpcache);
      send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_DPREP, 0, ied1.buf, ied1.pos, -1);
   }
   if (!skiplock)
      ast_mutex_unlock(&iaxsl[callno]);
}
static void* dp_lookup_thread ( void *  data) [static]

Definition at line 8921 of file chan_iax2.c.

References ast_free, dpreq_data::callednum, dpreq_data::callerid, dpreq_data::callno, dpreq_data::context, and dp_lookup().

Referenced by spawn_dp_lookup().

{
   /* Look up for dpreq */
   struct dpreq_data *dpr = data;
   dp_lookup(dpr->callno, dpr->context, dpr->callednum, dpr->callerid, 0);
   if (dpr->callerid)
      ast_free(dpr->callerid);
   ast_free(dpr);
   return NULL;
}
static void encmethods_to_str ( int  e,
struct ast_str buf 
) [static]

Definition at line 1440 of file chan_iax2.c.

References ast_str_append(), ast_str_set(), ast_str_strlen(), IAX_ENCRYPT_AES128, and IAX_ENCRYPT_KEYROTATE.

Referenced by __iax2_show_peers(), handle_cli_iax2_show_peer(), and manager_iax2_show_peer_list().

{
   ast_str_set(&buf, 0, "(");
   if (e & IAX_ENCRYPT_AES128) {
      ast_str_append(&buf, 0, "aes128");
   }
   if (e & IAX_ENCRYPT_KEYROTATE) {
      ast_str_append(&buf, 0, ",keyrotate");
   }
   if (ast_str_strlen(buf) > 1) {
      ast_str_append(&buf, 0, ")");
   } else {
      ast_str_set(&buf, 0, "No");
   }
}
static int encrypt_frame ( ast_aes_encrypt_key ecx,
struct ast_iax2_full_hdr fh,
unsigned char *  poo,
int *  datalen 
) [static]

Definition at line 6009 of file chan_iax2.c.

References ast_debug, ast_iax2_full_hdr::csub, ast_iax2_mini_enc_hdr::encdata, ast_iax2_full_enc_hdr::encdata, IAX_FLAG_FULL, memcpy_encrypt(), ast_iax2_full_hdr::scallno, and ast_iax2_full_hdr::type.

Referenced by iax2_send(), and update_packet().

{
   int padding;
   unsigned char *workspace;
   workspace = alloca(*datalen + 32);
   if (!workspace)
      return -1;
   if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
      struct ast_iax2_full_enc_hdr *efh = (struct ast_iax2_full_enc_hdr *)fh;
      if (iaxdebug)
         ast_debug(1, "Encoding full frame %d/%d with length %d\n", fh->type, fh->csub, *datalen);
      padding = 16 - ((*datalen - sizeof(struct ast_iax2_full_enc_hdr)) % 16);
      padding = 16 + (padding & 0xf);
      memcpy(workspace, poo, padding);
      memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
      workspace[15] &= 0xf0;
      workspace[15] |= (padding & 0xf);
      if (iaxdebug)
         ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
      *datalen += padding;
      memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
      if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
         memcpy(poo, workspace + *datalen - 32, 32);
   } else {
      struct ast_iax2_mini_enc_hdr *efh = (struct ast_iax2_mini_enc_hdr *)fh;
      if (iaxdebug)
         ast_debug(1, "Encoding mini frame with length %d\n", *datalen);
      padding = 16 - ((*datalen - sizeof(struct ast_iax2_mini_enc_hdr)) % 16);
      padding = 16 + (padding & 0xf);
      memcpy(workspace, poo, padding);
      memcpy(workspace + padding, efh->encdata, *datalen - sizeof(struct ast_iax2_mini_enc_hdr));
      workspace[15] &= 0xf0;
      workspace[15] |= (padding & 0x0f);
      *datalen += padding;
      memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_mini_enc_hdr), ecx);
      if (*datalen >= 32 + sizeof(struct ast_iax2_mini_enc_hdr))
         memcpy(poo, workspace + *datalen - 32, 32);
   }
   return 0;
}
static int expire_registry ( const void *  data) [static]

Definition at line 8320 of file chan_iax2.c.

References __expire_registry(), and schedule_action.

Referenced by handle_cli_iax2_prune_realtime(), handle_cli_iax2_unregister(), realtime_peer(), reg_source_db(), and update_registry().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__expire_registry, data))
#endif      
      __expire_registry(data);
   return 0;
}
static struct iax2_dpcache* find_cache ( struct ast_channel chan,
const char *  data,
const char *  context,
const char *  exten,
int  priority 
) [static, read]

Definition at line 13127 of file chan_iax2.c.

References ARRAY_LEN, ast_calloc, ast_channel_defer_dtmf(), ast_channel_undefer_dtmf(), ast_copy_string(), ast_free, ast_frfree, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_unlock(), ast_read(), ast_test_flag, ast_tvcmp(), ast_tvnow(), ast_waitfor_nandfds(), CACHE_FLAG_PENDING, CACHE_FLAG_TIMEOUT, cache_get_callno_locked(), iax2_dpcache::callno, errno, iax2_dpcache::expiry, iax2_dpcache::exten, f, iax2_dpcache::flags, iax2_dprequest(), IAX_STATE_STARTED, iaxdefaultdpcache, LOG_WARNING, iax2_dpcache::orig, iax2_dpcache::peercontext, and iax2_dpcache::waiters.

Referenced by iax2_canmatch(), iax2_exec(), iax2_exists(), and iax2_matchmore().

{
   struct iax2_dpcache *dp = NULL;
   struct timeval now = ast_tvnow();
   int x, com[2], timeout, old = 0, outfd, doabort, callno;
   struct ast_channel *c = NULL;
   struct ast_frame *f = NULL;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, cache_list) {
      if (ast_tvcmp(now, dp->expiry) > 0) {
         AST_LIST_REMOVE_CURRENT(cache_list);
         if ((dp->flags & CACHE_FLAG_PENDING) || dp->callno)
            ast_log(LOG_WARNING, "DP still has peer field or pending or callno (flags = %d, peer = blah, callno = %d)\n", dp->flags, dp->callno);
         else
            ast_free(dp);
         continue;
      }
      if (!strcmp(dp->peercontext, data) && !strcmp(dp->exten, exten))
         break;
   }
   AST_LIST_TRAVERSE_SAFE_END;

   if (!dp) {
      /* No matching entry.  Create a new one. */
      /* First, can we make a callno? */
      if ((callno = cache_get_callno_locked(data)) < 0) {
         ast_log(LOG_WARNING, "Unable to generate call for '%s'\n", data);
         return NULL;
      }
      if (!(dp = ast_calloc(1, sizeof(*dp)))) {
         ast_mutex_unlock(&iaxsl[callno]);
         return NULL;
      }
      ast_copy_string(dp->peercontext, data, sizeof(dp->peercontext));
      ast_copy_string(dp->exten, exten, sizeof(dp->exten));
      dp->expiry = ast_tvnow();
      dp->orig = dp->expiry;
      /* Expires in 30 mins by default */
      dp->expiry.tv_sec += iaxdefaultdpcache;
      dp->flags = CACHE_FLAG_PENDING;
      for (x = 0; x < ARRAY_LEN(dp->waiters); x++)
         dp->waiters[x] = -1;
      /* Insert into the lists */
      AST_LIST_INSERT_TAIL(&dpcache, dp, cache_list);
      AST_LIST_INSERT_TAIL(&iaxs[callno]->dpentries, dp, peer_list);
      /* Send the request if we're already up */
      if (ast_test_flag(&iaxs[callno]->state, IAX_STATE_STARTED))
         iax2_dprequest(dp, callno);
      ast_mutex_unlock(&iaxsl[callno]);
   }

   /* By here we must have a dp */
   if (dp->flags & CACHE_FLAG_PENDING) {
      /* Okay, here it starts to get nasty.  We need a pipe now to wait
         for a reply to come back so long as it's pending */
      for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
         /* Find an empty slot */
         if (dp->waiters[x] < 0)
            break;
      }
      if (x >= ARRAY_LEN(dp->waiters)) {
         ast_log(LOG_WARNING, "No more waiter positions available\n");
         return NULL;
      }
      if (pipe(com)) {
         ast_log(LOG_WARNING, "Unable to create pipe for comm\n");
         return NULL;
      }
      dp->waiters[x] = com[1];
      /* Okay, now we wait */
      timeout = iaxdefaulttimeout * 1000;
      /* Temporarily unlock */
      AST_LIST_UNLOCK(&dpcache);
      /* Defer any dtmf */
      if (chan)
         old = ast_channel_defer_dtmf(chan);
      doabort = 0;
      while(timeout) {
         c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
         if (outfd > -1)
            break;
         if (!c)
            continue;
         if (!(f = ast_read(c))) {
            doabort = 1;
            break;
         }
         ast_frfree(f);
      }
      if (!timeout) {
         ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
      }
      AST_LIST_LOCK(&dpcache);
      dp->waiters[x] = -1;
      close(com[1]);
      close(com[0]);
      if (doabort) {
         /* Don't interpret anything, just abort.  Not sure what th epoint
           of undeferring dtmf on a hung up channel is but hey whatever */
         if (!old && chan)
            ast_channel_undefer_dtmf(chan);
         return NULL;
      }
      if (!(dp->flags & CACHE_FLAG_TIMEOUT)) {
         /* Now to do non-independent analysis the results of our wait */
         if (dp->flags & CACHE_FLAG_PENDING) {
            /* Still pending... It's a timeout.  Wake everybody up.  Consider it no longer
               pending.  Don't let it take as long to timeout. */
            dp->flags &= ~CACHE_FLAG_PENDING;
            dp->flags |= CACHE_FLAG_TIMEOUT;
            /* Expire after only 60 seconds now.  This is designed to help reduce backlog in heavily loaded
               systems without leaving it unavailable once the server comes back online */
            dp->expiry.tv_sec = dp->orig.tv_sec + 60;
            for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
               if (dp->waiters[x] > -1) {
                  if (write(dp->waiters[x], "asdf", 4) < 0) {
                     ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
                  }
               }
            }
         }
      }
      /* Our caller will obtain the rest */
      if (!old && chan)
         ast_channel_undefer_dtmf(chan);
   }
   return dp;  
}
static int find_callno ( unsigned short  callno,
unsigned short  dcallno,
struct sockaddr_in *  sin,
int  new,
int  sockfd,
int  full_frame 
) [static]

Definition at line 2780 of file chan_iax2.c.

References __find_callno().

Referenced by iax2_poke_peer(), and socket_process().

                                                                                                                                    {

   return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
}
static int find_callno_locked ( unsigned short  callno,
unsigned short  dcallno,
struct sockaddr_in *  sin,
int  new,
int  sockfd,
int  full_frame 
) [static]

Definition at line 2785 of file chan_iax2.c.

References __find_callno().

Referenced by cache_get_callno_locked(), iax2_do_register(), iax2_provision(), iax2_request(), and socket_process_meta().

                                                                                                                                           {

   return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
}
static struct iax2_thread* find_idle_thread ( void  ) [static, read]

Definition at line 1298 of file chan_iax2.c.

References ast_atomic_fetchadd_int(), ast_calloc, ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, iax2_thread::cond, iax2_thread::ffinfo, iax2_process_thread(), IAX_THREAD_TYPE_DYNAMIC, iaxdynamicthreadcount, iaxdynamicthreadnum, iaxmaxthreadcount, iax2_thread::init_cond, iax2_thread::init_lock, iax2_thread::lock, thread, iax2_thread::threadid, iax2_thread::threadnum, and iax2_thread::type.

Referenced by __schedule_action(), and socket_read().

{
   struct iax2_thread *thread = NULL;

   /* Pop the head of the idle list off */
   AST_LIST_LOCK(&idle_list);
   thread = AST_LIST_REMOVE_HEAD(&idle_list, list);
   AST_LIST_UNLOCK(&idle_list);

   /* If we popped a thread off the idle list, just return it */
   if (thread) {
      memset(&thread->ffinfo, 0, sizeof(thread->ffinfo));
      return thread;
   }

   /* Pop the head of the dynamic list off */
   AST_LIST_LOCK(&dynamic_list);
   thread = AST_LIST_REMOVE_HEAD(&dynamic_list, list);
   AST_LIST_UNLOCK(&dynamic_list);

   /* If we popped a thread off the dynamic list, just return it */
   if (thread) {
      memset(&thread->ffinfo, 0, sizeof(thread->ffinfo));
      return thread;
   }

   /* If we can't create a new dynamic thread for any reason, return no thread at all */
   if (iaxdynamicthreadcount >= iaxmaxthreadcount || !(thread = ast_calloc(1, sizeof(*thread))))
      return NULL;

   /* Set default values */
   ast_atomic_fetchadd_int(&iaxdynamicthreadcount, 1);
   thread->threadnum = ast_atomic_fetchadd_int(&iaxdynamicthreadnum, 1);
   thread->type = IAX_THREAD_TYPE_DYNAMIC;

   /* Initialize lock and condition */
   ast_mutex_init(&thread->lock);
   ast_cond_init(&thread->cond, NULL);
   ast_mutex_init(&thread->init_lock);
   ast_cond_init(&thread->init_cond, NULL);
   ast_mutex_lock(&thread->init_lock);

   /* Create thread and send it on it's way */
   if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
      ast_cond_destroy(&thread->cond);
      ast_mutex_destroy(&thread->lock);
      ast_mutex_unlock(&thread->init_lock);
      ast_cond_destroy(&thread->init_cond);
      ast_mutex_destroy(&thread->init_lock);
      ast_free(thread);
      return NULL;
   }

   /* this thread is not processing a full frame (since it is idle),
      so ensure that the field for the full frame call number is empty */
   memset(&thread->ffinfo, 0, sizeof(thread->ffinfo));

   /* Wait for the thread to be ready before returning it to the caller */
   ast_cond_wait(&thread->init_cond, &thread->init_lock);

   /* Done with init_lock */
   ast_mutex_unlock(&thread->init_lock);

   return thread;
}
static struct iax2_peer* find_peer ( const char *  name,
int  realtime 
) [static, read]
Note:
This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno, so do not call it with a pvt lock held.

Definition at line 1579 of file chan_iax2.c.

References ao2_find, name, iax2_peer::name, OBJ_POINTER, and realtime_peer().

Referenced by calltoken_required(), create_addr(), function_iaxpeer(), handle_cli_iax2_prune_realtime(), handle_cli_iax2_set_debug(), handle_cli_iax2_show_peer(), handle_cli_iax2_unregister(), iax2_devicestate(), register_verify(), registry_authrequest(), requirecalltoken_mark_auto(), and update_registry().

{
   struct iax2_peer *peer = NULL;
   struct iax2_peer tmp_peer = {
      .name = name,
   };

   peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);

   /* Now go for realtime if applicable */
   if(!peer && realtime)
      peer = realtime_peer(name, NULL);

   return peer;
}
static struct iax2_trunk_peer* find_tpeer ( struct sockaddr_in *  sin,
int  fd 
) [static, read]

Definition at line 5782 of file chan_iax2.c.

References iax2_trunk_peer::addr, ast_calloc, ast_debug, ast_inet_ntoa(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_init(), ast_mutex_lock(), ast_tvnow(), inaddrcmp(), iax2_trunk_peer::lastsent, iax2_trunk_peer::lock, iax2_trunk_peer::sockfd, and iax2_trunk_peer::trunkact.

Referenced by iax2_trunk_queue(), and socket_process_meta().

{
   struct iax2_trunk_peer *tpeer = NULL;
   
   /* Finds and locks trunk peer */
   AST_LIST_LOCK(&tpeers);

   AST_LIST_TRAVERSE(&tpeers, tpeer, list) {
      if (!inaddrcmp(&tpeer->addr, sin)) {
         ast_mutex_lock(&tpeer->lock);
         break;
      }
   }

   if (!tpeer) {
      if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
         ast_mutex_init(&tpeer->lock);
         tpeer->lastsent = 9999;
         memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
         tpeer->trunkact = ast_tvnow();
         ast_mutex_lock(&tpeer->lock);
         tpeer->sockfd = fd;
#ifdef SO_NO_CHECK
         setsockopt(tpeer->sockfd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
#endif
         ast_debug(1, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
         AST_LIST_INSERT_TAIL(&tpeers, tpeer, list);
      }
   }

   AST_LIST_UNLOCK(&tpeers);

   return tpeer;
}
static struct iax2_user* find_user ( const char *  name) [static, read]

Definition at line 1607 of file chan_iax2.c.

References ao2_find, name, iax2_user::name, and OBJ_POINTER.

Referenced by calltoken_required(), handle_cli_iax2_prune_realtime(), and requirecalltoken_mark_auto().

{
   struct iax2_user tmp_user = {
      .name = name,
   };

   return ao2_find(users, &tmp_user, OBJ_POINTER);
}
static unsigned int fix_peerts ( struct timeval *  rxtrunktime,
int  callno,
unsigned int  ts 
) [static]

Definition at line 5594 of file chan_iax2.c.

References ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), and chan_iax2_pvt::rxcore.

Referenced by socket_process_meta().

{
   long ms; /* NOT unsigned */
   if (ast_tvzero(iaxs[callno]->rxcore)) {
      /* Initialize rxcore time if appropriate */
      iaxs[callno]->rxcore = ast_tvnow();
      /* Round to nearest 20ms so traces look pretty */
      iaxs[callno]->rxcore.tv_usec -= iaxs[callno]->rxcore.tv_usec % 20000;
   }
   /* Calculate difference between trunk and channel */
   ms = ast_tvdiff_ms(*rxtrunktime, iaxs[callno]->rxcore);
   /* Return as the sum of trunk time and the difference between trunk and real time */
   return ms + ts;
}
static void free_context ( struct iax2_context con) [static]

Definition at line 11597 of file chan_iax2.c.

References ast_free, and iax2_context::next.

Referenced by build_user(), and user_destructor().

{
   struct iax2_context *conl;
   while(con) {
      conl = con;
      con = con->next;
      ast_free(conl);
   }
}
static void free_signaling_queue_entry ( struct signaling_queue_entry s) [static]
static int function_iaxpeer ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 13377 of file chan_iax2.c.

References iax2_peer::addr, iax2_trunk_peer::addr, ast_codec_pref_index(), ast_copy_string(), ast_getformatname(), ast_getformatname_multiple(), ast_inet_ntoa(), ast_strdupa, ast_test_flag, iax2_peer::callno, iax2_peer::capability, iax2_peer::cid_name, iax2_peer::cid_num, iax2_peer::context, iax2_peer::expire, find_peer(), IAX_DYNAMIC, iax2_peer::mailbox, peer_status(), peer_unref(), iax2_peer::prefs, PTR_TO_CALLNO, ast_channel::tech, and ast_channel::tech_pvt.

{
   struct iax2_peer *peer;
   char *peername, *colname;

   peername = ast_strdupa(data);

   /* if our channel, return the IP address of the endpoint of current channel */
   if (!strcmp(peername,"CURRENTCHANNEL")) {
           unsigned short callno;
      if (chan->tech != &iax2_tech)
         return -1;
      callno = PTR_TO_CALLNO(chan->tech_pvt);   
      ast_copy_string(buf, iaxs[callno]->addr.sin_addr.s_addr ? ast_inet_ntoa(iaxs[callno]->addr.sin_addr) : "", len);
      return 0;
   }

   if ((colname = strchr(peername, ',')))
      *colname++ = '\0';
   else
      colname = "ip";

   if (!(peer = find_peer(peername, 1)))
      return -1;

   if (!strcasecmp(colname, "ip")) {
      ast_copy_string(buf, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "", len);
   } else  if (!strcasecmp(colname, "status")) {
      peer_status(peer, buf, len); 
   } else  if (!strcasecmp(colname, "mailbox")) {
      ast_copy_string(buf, peer->mailbox, len);
   } else  if (!strcasecmp(colname, "context")) {
      ast_copy_string(buf, peer->context, len);
   } else  if (!strcasecmp(colname, "expire")) {
      snprintf(buf, len, "%d", peer->expire);
   } else  if (!strcasecmp(colname, "dynamic")) {
      ast_copy_string(buf, (ast_test_flag(peer, IAX_DYNAMIC) ? "yes" : "no"), len);
   } else  if (!strcasecmp(colname, "callerid_name")) {
      ast_copy_string(buf, peer->cid_name, len);
   } else  if (!strcasecmp(colname, "callerid_num")) {
      ast_copy_string(buf, peer->cid_num, len);
   } else  if (!strcasecmp(colname, "codecs")) {
      ast_getformatname_multiple(buf, len -1, peer->capability);
   } else  if (!strncasecmp(colname, "codec[", 6)) {
      char *codecnum, *ptr;
      int codec = 0;
      
      codecnum = strchr(colname, '[');
      *codecnum = '\0';
      codecnum++;
      if ((ptr = strchr(codecnum, ']'))) {
         *ptr = '\0';
      }
      if((codec = ast_codec_pref_index(&peer->prefs, atoi(codecnum)))) {
         ast_copy_string(buf, ast_getformatname(codec), len);
      } else {
         buf[0] = '\0';
      }
   } else {
      buf[0] = '\0';
   }

   peer_unref(peer);

   return 0;
}
static int get_auth_methods ( const char *  value) [static]

Definition at line 11795 of file chan_iax2.c.

References IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, and IAX_AUTH_RSA.

Referenced by build_peer(), and build_user().

{
   int methods = 0;
   if (strstr(value, "rsa"))
      methods |= IAX_AUTH_RSA;
   if (strstr(value, "md5"))
      methods |= IAX_AUTH_MD5;
   if (strstr(value, "plaintext"))
      methods |= IAX_AUTH_PLAINTEXT;
   return methods;
}
static int get_encrypt_methods ( const char *  s) [static]

Definition at line 1456 of file chan_iax2.c.

References ast_true(), IAX_ENCRYPT_AES128, and IAX_ENCRYPT_KEYROTATE.

Referenced by build_peer(), build_user(), and set_config().

{
   int e;
   if (!strcasecmp(s, "aes128"))
      e = IAX_ENCRYPT_AES128 | IAX_ENCRYPT_KEYROTATE;
   else if (ast_true(s))
      e = IAX_ENCRYPT_AES128 | IAX_ENCRYPT_KEYROTATE;
   else
      e = 0;
   return e;
}
static int get_from_jb ( const void *  p) [static]

Definition at line 3977 of file chan_iax2.c.

References __get_from_jb(), and schedule_action.

Referenced by update_jbsched().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__get_from_jb, data))
#endif      
      __get_from_jb(data);
   return 0;
}
static struct callno_entry * get_unused_callno ( int  trunk,
int  validated 
) [static, read]

Definition at line 2458 of file chan_iax2.c.

References ao2_container_count(), ao2_find, ao2_lock(), ao2_unlock(), ast_log(), LOG_WARNING, OBJ_CONTINUE, OBJ_POINTER, OBJ_UNLINK, and callno_entry::validated.

Referenced by __find_callno(), and make_trunk().

{
   struct callno_entry *callno_entry = NULL;
   if ((!ao2_container_count(callno_pool) && !trunk) || (!ao2_container_count(callno_pool_trunk) && trunk)) {
      ast_log(LOG_WARNING, "Out of CallNumbers\n");
      /* Minor optimization for the extreme case. */
      return NULL;
   }

   /* the callno_pool container is locked here primarily to ensure thread
    * safety of the total_nonval_callno_used check and increment */
   ao2_lock(callno_pool);

   /* only a certain number of nonvalidated call numbers should be allocated.
    * If there ever is an attack, this separates the calltoken validating
    * users from the non calltoken validating users. */
   if (!validated && (total_nonval_callno_used >= global_maxcallno_nonval)) {
      ast_log(LOG_WARNING, "NON-CallToken callnumber limit is reached. Current:%d Max:%d\n", total_nonval_callno_used, global_maxcallno_nonval);
      ao2_unlock(callno_pool);
      return NULL;
   }

   /* unlink the object from the container, taking over ownership
    * of the reference the container had to the object */
   callno_entry = ao2_find((trunk ? callno_pool_trunk : callno_pool), NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE);

   if (callno_entry) {
      callno_entry->validated = validated;
      if (!validated) {
         total_nonval_callno_used++;
      }
   }

   ao2_unlock(callno_pool);
   return callno_entry;
}
static int handle_call_token ( struct ast_iax2_full_hdr fh,
struct iax_ies ies,
struct sockaddr_in *  sin,
int  fd 
) [static]

Definition at line 4667 of file chan_iax2.c.

References ast_inet_ntoa(), ast_log(), ast_sha1_hash(), ast_str_alloca, ast_str_buffer(), ast_str_set(), iax_ie_data::buf, iax_ies::calltoken, CALLTOKEN_HASH_FORMAT, CALLTOKEN_IE_FORMAT, calltoken_required(), iax_ies::calltokendata, ast_iax2_full_hdr::csub, IAX_COMMAND_CALLTOKEN, IAX_COMMAND_REGREJ, IAX_COMMAND_REGREL, IAX_COMMAND_REGREQ, IAX_COMMAND_REJECT, iax_ie_append_str(), IAX_IE_CALLTOKEN, ast_iax2_full_hdr::iseqno, LOG_ERROR, LOG_WARNING, requirecalltoken_mark_auto(), S_OR, ast_iax2_full_hdr::scallno, send_apathetic_reply(), ast_iax2_full_hdr::ts, uncompress_subclass(), and iax_ies::username.

Referenced by socket_process().

{
#define CALLTOKEN_HASH_FORMAT "%s%d%u%d"  /* address + port + ts + randomcalldata */
#define CALLTOKEN_IE_FORMAT   "%u?%s"     /* time + ? + (40 char hash) */
   struct ast_str *buf = ast_str_alloca(256);
   time_t t = time(NULL);
   char hash[41]; /* 40 char sha1 hash */
   int subclass = uncompress_subclass(fh->csub);

   /* ----- Case 1 ----- */
   if (ies->calltoken && !ies->calltokendata) {  /* empty calltoken is provided, client supports calltokens */
      struct iax_ie_data ied = {
         .buf = { 0 },
         .pos = 0,
      };

      /* create the hash with their address data and our timestamp */
      ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) t, randomcalltokendata);
      ast_sha1_hash(hash, ast_str_buffer(buf));

      ast_str_set(&buf, 0, CALLTOKEN_IE_FORMAT, (unsigned int) t, hash);
      iax_ie_append_str(&ied, IAX_IE_CALLTOKEN, ast_str_buffer(buf));
      send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);

      return 1;

   /* ----- Case 2 ----- */
   } else if (ies->calltoken && ies->calltokendata) { /* calltoken received, check to see if it is valid */
      char *rec_hash = NULL;    /* the received hash, make sure it matches with ours. */
      char *rec_ts = NULL;      /* received timestamp */
      unsigned int rec_time;  /* received time_t */

      /* split the timestamp from the hash data */
      rec_hash = strchr((char *) ies->calltokendata, '?');
      if (rec_hash) {
         *rec_hash++ = '\0';
         rec_ts = (char *) ies->calltokendata;
      }

      /* check that we have valid data before we do any comparisons */
      if (!rec_hash || !rec_ts) {
         goto reject;
      } else if (sscanf(rec_ts, "%u", &rec_time) != 1) {
         goto reject;
      }

      /* create a hash with their address and the _TOKEN'S_ timestamp */
      ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) rec_time, randomcalltokendata);
      ast_sha1_hash(hash, ast_str_buffer(buf));

      /* compare hashes and then check timestamp delay */
      if (strcmp(hash, rec_hash)) {
         ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_inet_ntoa(sin->sin_addr));
         goto reject; /* received hash does not match ours, reject */
      } else if ((t < rec_time) || ((t - rec_time) >= MAX_CALLTOKEN_DELAY)) {
         ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_inet_ntoa(sin->sin_addr));
         goto reject; /* too much delay, reject */
      }

      /* at this point the call token is valid, returning 0 
       * will allow socket_process to continue as usual */
      requirecalltoken_mark_auto(ies->username, subclass);
      return 0;

   /* ----- Case 3 ----- */
   } else { /* calltokens are not supported for this client, how do we respond? */
      if (calltoken_required(sin, ies->username, subclass)) {
         ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_inet_ntoa(sin->sin_addr), S_OR(ies->username, "guest"));
         goto reject;
      }
      return 0; /* calltoken is not required for this addr, so permit it. */
   }

reject:
   /* received frame has failed calltoken inspection, send apathetic reject messages */
   if (subclass == IAX_COMMAND_REGREQ || subclass == IAX_COMMAND_REGREL) {
      send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
   } else {
      send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
   }

   return 1;
}
static char* handle_cli_iax2_provision ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 11448 of file chan_iax2.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, iax2_provision(), iax_prov_complete_template(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   int force = 0;
   int res;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 provision";
      e->usage = 
         "Usage: iax2 provision <host> <template> [forced]\n"
         "       Provisions the given peer or IP address using a template\n"
         "       matching either 'template' or '*' if the template is not\n"
         "       found.  If 'forced' is specified, even empty provisioning\n"
         "       fields will be provisioned as empty fields.\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 3)
         return iax_prov_complete_template(a->line, a->word, a->pos, a->n);
      return NULL;
   }

   if (a->argc < 4)
      return CLI_SHOWUSAGE;
   if (a->argc > 4) {
      if (!strcasecmp(a->argv[4], "forced"))
         force = 1;
      else
         return CLI_SHOWUSAGE;
   }
   res = iax2_provision(NULL, -1, a->argv[2], a->argv[3], force);
   if (res < 0)
      ast_cli(a->fd, "Unable to find peer/address '%s'\n", a->argv[2]);
   else if (res < 1)
      ast_cli(a->fd, "No template (including wildcard) matching '%s'\n", a->argv[3]);
   else
      ast_cli(a->fd, "Provisioning '%s' with template '%s'%s\n", a->argv[2], a->argv[3], force ? ", forced" : "");
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_prune_realtime ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3415 of file chan_iax2.c.

References ao2_unlink, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_cli_complete(), ast_set_flag, ast_test_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_iax2_peers(), expire_registry(), ast_cli_args::fd, find_peer(), find_user(), IAX_RTAUTOCLEAR, IAX_RTCACHEFRIENDS, ast_cli_args::line, ast_cli_args::n, peer_ref(), peer_unref(), ast_cli_args::pos, prune_peers(), prune_users(), ast_cli_entry::usage, user_unref(), and ast_cli_args::word.

{
   struct iax2_peer *peer = NULL;
   struct iax2_user *user = NULL;
   static char *choices[] = { "all", NULL };
   char *cmplt;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 prune realtime";
      e->usage =
         "Usage: iax2 prune realtime [<peername>|all]\n"
         "       Prunes object(s) from the cache\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 3) {
         cmplt = ast_cli_complete(a->word, choices, a->n);
         if (!cmplt)
            cmplt = complete_iax2_peers(a->line, a->word, a->pos, a->n - sizeof(choices), IAX_RTCACHEFRIENDS);
         return cmplt;
      }
      return NULL;
   }
   if (a->argc != 4)
      return CLI_SHOWUSAGE;
   if (!strcmp(a->argv[3], "all")) {
      prune_users();
      prune_peers();
      ast_cli(a->fd, "Cache flushed successfully.\n");
      return CLI_SUCCESS;
   }
   peer = find_peer(a->argv[3], 0);
   user = find_user(a->argv[3]);
   if (peer || user) {
      if (peer) {
         if (ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
            ast_set_flag(peer, IAX_RTAUTOCLEAR);
            expire_registry(peer_ref(peer));
            ast_cli(a->fd, "Peer %s was removed from the cache.\n", a->argv[3]);
         } else {
            ast_cli(a->fd, "Peer %s is not eligible for this operation.\n", a->argv[3]);
         }
         peer_unref(peer);
      }
      if (user) {
         if (ast_test_flag(user, IAX_RTCACHEFRIENDS)) {
            ast_set_flag(user, IAX_RTAUTOCLEAR);
            ast_cli(a->fd, "User %s was removed from the cache.\n", a->argv[3]);
         } else {
            ast_cli(a->fd, "User %s is not eligible for this operation.\n", a->argv[3]);
         }
         ao2_unlink(users,user);
         user_unref(user);
      }
   } else {
      ast_cli(a->fd, "%s was not found in the cache.\n", a->argv[3]);
   }

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 13031 of file chan_iax2.c.

References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, reload_config(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 reload";
      e->usage =
         "Usage: iax2 reload\n"
         "       Reloads IAX configuration from iax.conf\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   reload_config();

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7032 of file chan_iax2.c.

References iax2_peer::addr, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_inet_ntoa(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_iax2_peers(), debugaddr, ast_cli_args::fd, find_peer(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 set debug {on|off|peer}";
      e->usage =
         "Usage: iax2 set debug {on|off|peer peername}\n"
         "       Enables/Disables dumping of IAX packets for debugging purposes.\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 4 && !strcasecmp(a->argv[3], "peer"))
         return complete_iax2_peers(a->line, a->word, a->pos, a->n, 0);
      return NULL;
   }

   if (a->argc < e->args  || a->argc > e->args + 1)
      return CLI_SHOWUSAGE;

   if (!strcasecmp(a->argv[3], "peer")) {
      struct iax2_peer *peer;

      if (a->argc != e->args + 1)
         return CLI_SHOWUSAGE;

      peer = find_peer(a->argv[4], 1);

      if (!peer) {
         ast_cli(a->fd, "IAX2 peer '%s' does not exist\n", a->argv[e->args-1]);
         return CLI_FAILURE;
      }

      debugaddr.sin_addr = peer->addr.sin_addr;
      debugaddr.sin_port = peer->addr.sin_port;

      ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%d\n",
         ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));

      ao2_ref(peer, -1);
   } else if (!strncasecmp(a->argv[3], "on", 2)) {
      iaxdebug = 1;
      ast_cli(a->fd, "IAX2 Debugging Enabled\n");
   } else {
      iaxdebug = 0;
      memset(&debugaddr, 0, sizeof(debugaddr));
      ast_cli(a->fd, "IAX2 Debugging Disabled\n");
   }
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_set_debug_jb ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7107 of file chan_iax2.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, jb_debug_output(), jb_error_output(), jb_setoutput(), jb_warning_output(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 set debug jb {on|off}";
      e->usage =
         "Usage: iax2 set debug jb {on|off}\n"
         "       Enables/Disables jitterbuffer debugging information\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;
   
   if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
      jb_setoutput(jb_error_output, jb_warning_output, jb_debug_output);
      ast_cli(a->fd, "IAX2 Jitterbuffer Debugging Enabled\n");
   } else {
      jb_setoutput(jb_error_output, jb_warning_output, NULL);
      ast_cli(a->fd, "IAX2 Jitterbuffer Debugging Disabled\n");
   }
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_set_debug_trunk ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7081 of file chan_iax2.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.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 set debug trunk {on|off}";
      e->usage =
         "Usage: iax2 set debug trunk {on|off}\n"
         "       Enables/Disables debugging of IAX trunking\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
      iaxtrunkdebug = 1;
      ast_cli(a->fd, "IAX2 Trunk Debugging Enabled\n");
   } else {
      iaxtrunkdebug = 0;
      ast_cli(a->fd, "IAX2 Trunk Debugging Disabled\n");
   }
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_set_mtu ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Set trunk MTU from CLI.

Definition at line 3736 of file chan_iax2.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, MAX_TRUNK_MTU, and ast_cli_entry::usage.

{
   int mtuv;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 set mtu";
      e->usage =
         "Usage: iax2 set mtu <value>\n"
         "       Set the system-wide IAX IP mtu to <value> bytes net or\n"
         "       zero to disable. Disabling means that the operating system\n"
         "       must handle fragmentation of UDP packets when the IAX2 trunk\n"
         "       packet exceeds the UDP payload size. This is substantially\n"
         "       below the IP mtu. Try 1240 on ethernets. Must be 172 or\n"
         "       greater for G.711 samples.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4)
      return CLI_SHOWUSAGE; 
   if (strncasecmp(a->argv[3], "default", strlen(a->argv[3])) == 0)
      mtuv = MAX_TRUNK_MTU;
   else
      mtuv = atoi(a->argv[3]);

   if (mtuv == 0) {
      ast_cli(a->fd, "Trunk MTU control disabled (mtu was %d)\n", global_max_trunk_mtu); 
      global_max_trunk_mtu = 0; 
      return CLI_SUCCESS; 
   }
   if (mtuv < 172 || mtuv > 4000) {
      ast_cli(a->fd, "Trunk MTU must be between 172 and 4000\n"); 
      return CLI_SHOWUSAGE; 
   }
   ast_cli(a->fd, "Trunk MTU changed from %d to %d\n", global_max_trunk_mtu, mtuv); 
   global_max_trunk_mtu = mtuv; 
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_cache ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3777 of file chan_iax2.c.

References ARRAY_LEN, ast_cli(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_tvnow(), CACHE_FLAG_CANEXIST, CACHE_FLAG_EXISTS, CACHE_FLAG_MATCHMORE, CACHE_FLAG_NONEXISTENT, CACHE_FLAG_PENDING, CACHE_FLAG_TIMEOUT, CACHE_FLAG_TRANSMITTED, CACHE_FLAG_UNKNOWN, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, iax2_dpcache::expiry, iax2_dpcache::exten, ast_cli_args::fd, iax2_dpcache::flags, iax2_dpcache::peercontext, s, ast_cli_entry::usage, and iax2_dpcache::waiters.

{
   struct iax2_dpcache *dp = NULL;
   char tmp[1024], *pc = NULL;
   int s, x, y;
   struct timeval now = ast_tvnow();

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show cache";
      e->usage =
         "Usage: iax2 show cache\n"
         "       Display currently cached IAX Dialplan results.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   AST_LIST_LOCK(&dpcache);

   ast_cli(a->fd, "%-20.20s %-12.12s %-9.9s %-8.8s %s\n", "Peer/Context", "Exten", "Exp.", "Wait.", "Flags");

   AST_LIST_TRAVERSE(&dpcache, dp, cache_list) {
      s = dp->expiry.tv_sec - now.tv_sec;
      tmp[0] = '\0';
      if (dp->flags & CACHE_FLAG_EXISTS)
         strncat(tmp, "EXISTS|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_NONEXISTENT)
         strncat(tmp, "NONEXISTENT|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_CANEXIST)
         strncat(tmp, "CANEXIST|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_PENDING)
         strncat(tmp, "PENDING|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_TIMEOUT)
         strncat(tmp, "TIMEOUT|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_TRANSMITTED)
         strncat(tmp, "TRANSMITTED|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_MATCHMORE)
         strncat(tmp, "MATCHMORE|", sizeof(tmp) - strlen(tmp) - 1);
      if (dp->flags & CACHE_FLAG_UNKNOWN)
         strncat(tmp, "UNKNOWN|", sizeof(tmp) - strlen(tmp) - 1);
      /* Trim trailing pipe */
      if (!ast_strlen_zero(tmp)) {
         tmp[strlen(tmp) - 1] = '\0';
      } else {
         ast_copy_string(tmp, "(none)", sizeof(tmp));
      }
      y = 0;
      pc = strchr(dp->peercontext, '@');
      if (!pc) {
         pc = dp->peercontext;
      } else {
         pc++;
      }
      for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
         if (dp->waiters[x] > -1)
            y++;
      }
      if (s > 0) {
         ast_cli(a->fd, "%-20.20s %-12.12s %-9d %-8d %s\n", pc, dp->exten, s, y, tmp);
      } else {
         ast_cli(a->fd, "%-20.20s %-12.12s %-9.9s %-8d %s\n", pc, dp->exten, "(expired)", y, tmp);
      }
   }

   AST_LIST_UNLOCK(&dpcache);

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_callno_limits ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2411 of file chan_iax2.c.

References peercnt::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_inet_ntoa(), CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, peercnt::cur, ast_cli_args::fd, peercnt::limit, and ast_cli_entry::usage.

{
   struct ao2_iterator i;
   struct peercnt *peercnt;
   struct sockaddr_in sin;
   int found = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show callnumber usage";
      e->usage =
         "Usage: iax2 show callnumber usage <ip address (optional)>\n"
         "       Shows current ip addresses which are consuming iax2 call numbers\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   case CLI_HANDLER:
      if (a->argc < 4 || a->argc > 5)
         return CLI_SHOWUSAGE;

      ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
      i = ao2_iterator_init(peercnts, 0);
      while ((peercnt = ao2_iterator_next(&i))) {
         sin.sin_addr.s_addr = peercnt->addr;
         if (a->argc == 5 && (!strcasecmp(a->argv[4], ast_inet_ntoa(sin.sin_addr)))) {
               ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
               found = 1;
               break;
         } else {
            ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
         }
         ao2_ref(peercnt, -1);
      }
      ao2_iterator_destroy(&i);

      if (a->argc == 4) {
         ast_cli(a->fd, "\nNon-CallToken Validation Limit: %d\nNon-CallToken Validated: %d\n", global_maxcallno_nonval, total_nonval_callno_used);
      } else if (a->argc == 5 && !found) {
         ast_cli(a->fd, "No callnumber table entries for %s found\n", a->argv[4] );
      }

      return CLI_SUCCESS;
   default:
      return NULL;
   }
}
static char* handle_cli_iax2_show_channels ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6859 of file chan_iax2.c.

References iax2_trunk_peer::addr, ast_cli_args::argc, ARRAY_LEN, ast_cli(), ast_getformatname(), ast_inet_ntoa(), ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, iax2_registry::callno, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, jb_info::current, iax_rr::delay, ast_cli_args::fd, FORMAT, FORMAT2, iax_frame_subclass2str(), IAX_USEJITTERBUF, jb_getinfo(), jb_info::jitter, MARK_IAX_SUBCLASS_TX, jb_info::min, ast_channel::name, chan_iax2_pvt::owner, chan_iax2_pvt::remote_rr, S_OR, and ast_cli_entry::usage.

{
#define FORMAT2 "%-20.20s  %-15.15s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
#define FORMAT  "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
#define FORMATB "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
   int x;
   int numchans = 0;
   char first_message[10] = { 0, };
   char last_message[10] = { 0, };

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show channels";
      e->usage =
         "Usage: iax2 show channels\n"
         "       Lists all currently active IAX channels.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3)
      return CLI_SHOWUSAGE;
   ast_cli(a->fd, FORMAT2, "Channel", "Peer", "Username", "ID (Lo/Rem)", "Seq (Tx/Rx)", "Lag", "Jitter", "JitBuf", "Format", "FirstMsg", "LastMsg");
   for (x = 0; x < ARRAY_LEN(iaxs); x++) {
      ast_mutex_lock(&iaxsl[x]);
      if (iaxs[x]) {
         int lag, jitter, localdelay;
         jb_info jbinfo;
         if (ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
            jb_getinfo(iaxs[x]->jb, &jbinfo);
            jitter = jbinfo.jitter;
            localdelay = jbinfo.current - jbinfo.min;
         } else {
            jitter = -1;
            localdelay = 0;
         }

         iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message));
         iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message));
         lag = iaxs[x]->remote_rr.delay;
         ast_cli(a->fd, FORMAT,
            iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
            ast_inet_ntoa(iaxs[x]->addr.sin_addr),
            S_OR(iaxs[x]->username, "(None)"),
            iaxs[x]->callno, iaxs[x]->peercallno,
            iaxs[x]->oseqno, iaxs[x]->iseqno,
            lag,
            jitter,
            localdelay,
            ast_getformatname(iaxs[x]->voiceformat),
            (iaxs[x]->first_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
            first_message,
            (iaxs[x]->last_iax_message & MARK_IAX_SUBCLASS_TX) ? "Tx:" : "Rx:",
            last_message);
         numchans++;
      }
      ast_mutex_unlock(&iaxsl[x]);
   }
   ast_cli(a->fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
   return CLI_SUCCESS;
#undef FORMAT
#undef FORMAT2
#undef FORMATB
}
static char* handle_cli_iax2_show_firmware ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6656 of file chan_iax2.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_iax2_firmware_header::datalen, ast_iax2_firmware_header::devname, ast_cli_args::fd, iax_firmware::fwh, ast_cli_entry::usage, and ast_iax2_firmware_header::version.

{
   struct iax_firmware *cur = NULL;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show firmware";
      e->usage =
         "Usage: iax2 show firmware\n"
         "       Lists all known IAX firmware images.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3 && a->argc != 4)
      return CLI_SHOWUSAGE;

   ast_cli(a->fd, "%-15.15s  %-15.15s %-15.15s\n", "Device", "Version", "Size");
   AST_LIST_LOCK(&firmwares);
   AST_LIST_TRAVERSE(&firmwares, cur, list) {
      if ((a->argc == 3) || (!strcasecmp(a->argv[3], (char *) cur->fwh->devname)))  {
         ast_cli(a->fd, "%-15.15s  %-15d %-15d\n", cur->fwh->devname, 
            ntohs(cur->fwh->version), (int)ntohl(cur->fwh->datalen));
      }
   }
   AST_LIST_UNLOCK(&firmwares);

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_netstats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7009 of file chan_iax2.c.

References ast_cli_args::argc, ast_cli(), ast_cli_netstats(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   int numchans = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show netstats";
      e->usage =
         "Usage: iax2 show netstats\n"
         "       Lists network status for all currently active IAX channels.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc != 3)
      return CLI_SHOWUSAGE;
   ast_cli(a->fd, "                           -------- LOCAL ---------------------  -------- REMOTE --------------------\n");
   ast_cli(a->fd, "Channel               RTT  Jit  Del  Lost   %%  Drop  OOO  Kpkts  Jit  Del  Lost   %%  Drop  OOO  Kpkts FirstMsg    LastMsg\n");
   numchans = ast_cli_netstats(NULL, a->fd, 1);
   ast_cli(a->fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_peer ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show one peer in detail.

Definition at line 3590 of file chan_iax2.c.

References iax2_peer::addr, ast_cli_args::argc, ast_cli_args::argv, ast_callerid_merge(), ast_cli(), ast_codec_pref_index(), ast_getformatname(), ast_getformatname_multiple(), ast_inet_ntoa(), ast_str_alloca, ast_str_buffer(), ast_strlen_zero(), ast_test_flag, CALLTOKEN_AUTO, iax2_peer::calltoken_required, CALLTOKEN_YES, iax2_peer::capability, iax2_peer::cid_name, iax2_peer::cid_num, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_iax2_peers(), iax2_peer::context, iax2_peer::defaddr, iax2_peer::encmethods, encmethods_to_str(), iax2_peer::expire, ast_cli_args::fd, find_peer(), iax2_peer::ha, IAX_DYNAMIC, IAX_TRUNK, ast_cli_args::line, iax2_peer::mailbox, iax2_peer::maxcallno, ast_cli_args::n, iax2_peer::name, iax2_peer::parkinglot, peer_status(), peer_unref(), iax2_peer::pokefreqnotok, iax2_peer::pokefreqok, ast_cli_args::pos, iax2_peer::prefs, iax2_peer::secret, iax2_peer::smoothing, status, ast_cli_entry::usage, iax2_peer::username, and ast_cli_args::word.

{
   char status[30];
   char cbuf[256];
   struct iax2_peer *peer;
   char codec_buf[512];
   struct ast_str *encmethods = ast_str_alloca(256);
   int x = 0, codec = 0, load_realtime = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show peer";
      e->usage =
         "Usage: iax2 show peer <name>\n"
         "       Display details on specific IAX peer\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 3)
         return complete_iax2_peers(a->line, a->word, a->pos, a->n, 0);
      return NULL;
   }

   if (a->argc < 4)
      return CLI_SHOWUSAGE;

   load_realtime = (a->argc == 5 && !strcmp(a->argv[4], "load")) ? 1 : 0;

   peer = find_peer(a->argv[3], load_realtime);
   if (peer) {
      encmethods_to_str(peer->encmethods, encmethods);
      ast_cli(a->fd, "\n\n");
      ast_cli(a->fd, "  * Name       : %s\n", peer->name);
      ast_cli(a->fd, "  Secret       : %s\n", ast_strlen_zero(peer->secret) ? "<Not set>" : "<Set>");
      ast_cli(a->fd, "  Context      : %s\n", peer->context);
      ast_cli(a->fd, "  Parking lot  : %s\n", peer->parkinglot);
      ast_cli(a->fd, "  Mailbox      : %s\n", peer->mailbox);
      ast_cli(a->fd, "  Dynamic      : %s\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes" : "No");
      ast_cli(a->fd, "  Callnum limit: %d\n", peer->maxcallno);
      ast_cli(a->fd, "  Calltoken req: %s\n", (peer->calltoken_required == CALLTOKEN_YES) ? "Yes" : ((peer->calltoken_required == CALLTOKEN_AUTO) ? "Auto" : "No"));
      ast_cli(a->fd, "  Trunk        : %s\n", ast_test_flag(peer, IAX_TRUNK) ? "Yes" : "No");
      ast_cli(a->fd, "  Encryption   : %s\n", peer->encmethods ? ast_str_buffer(encmethods) : "No");
      ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
      ast_cli(a->fd, "  Expire       : %d\n", peer->expire);
      ast_cli(a->fd, "  ACL          : %s\n", (peer->ha ? "Yes" : "No"));
      ast_cli(a->fd, "  Addr->IP     : %s Port %d\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
      ast_cli(a->fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
      ast_cli(a->fd, "  Username     : %s\n", peer->username);
      ast_cli(a->fd, "  Codecs       : ");
      ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
      ast_cli(a->fd, "%s\n", codec_buf);

      ast_cli(a->fd, "  Codec Order  : (");
      for(x = 0; x < 32 ; x++) {
         codec = ast_codec_pref_index(&peer->prefs,x);
         if(!codec)
            break;
         ast_cli(a->fd, "%s", ast_getformatname(codec));
         if(x < 31 && ast_codec_pref_index(&peer->prefs,x+1))
            ast_cli(a->fd, "|");
      }

      if (!x)
         ast_cli(a->fd, "none");
      ast_cli(a->fd, ")\n");

      ast_cli(a->fd, "  Status       : ");
      peer_status(peer, status, sizeof(status));   
      ast_cli(a->fd, "%s\n",status);
      ast_cli(a->fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
      ast_cli(a->fd, "\n");
      peer_unref(peer);
   } else {
      ast_cli(a->fd, "Peer %s not found.\n", a->argv[3]);
      ast_cli(a->fd, "\n");
   }

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_peers ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6624 of file chan_iax2.c.

References __iax2_show_peers(), ast_cli_args::argc, ast_cli_args::argv, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show peers";
      e->usage =
         "Usage: iax2 show peers [registered] [like <pattern>]\n"
         "       Lists all known IAX2 peers.\n"
         "       Optional 'registered' argument lists only peers with known addresses.\n"
         "       Optional regular expression pattern is used to filter the peer list.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   switch (__iax2_show_peers(0, a->fd, NULL, a->argc, a->argv)) {
   case RESULT_SHOWUSAGE:
      return CLI_SHOWUSAGE;
   case RESULT_FAILURE:
      return CLI_FAILURE;
   default:
      return CLI_SUCCESS;
   }
}
static char* handle_cli_iax2_show_registry ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6768 of file chan_iax2.c.

References iax2_registry::addr, ast_cli_args::argc, ast_cli(), ast_copy_string(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, iax2_registry::dnsmgr, ast_cli_args::fd, FORMAT, FORMAT2, iax2_registry::refresh, iax2_registry::regstate, regstate2str(), iax2_registry::us, ast_cli_entry::usage, and iax2_registry::username.

{
#define FORMAT2 "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8.8s  %s\n"
#define FORMAT  "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8d  %s\n"
   struct iax2_registry *reg = NULL;
   char host[80];
   char perceived[80];
   int counter = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show registry";
      e->usage =
         "Usage: iax2 show registry\n"
         "       Lists all registration requests and status.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc != 3)
      return CLI_SHOWUSAGE;
   ast_cli(a->fd, FORMAT2, "Host", "dnsmgr", "Username", "Perceived", "Refresh", "State");
   AST_LIST_LOCK(&registrations);
   AST_LIST_TRAVERSE(&registrations, reg, entry) {
      snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(reg->addr.sin_addr), ntohs(reg->addr.sin_port));
      if (reg->us.sin_addr.s_addr) 
         snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
      else
         ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
      ast_cli(a->fd, FORMAT, host, 
               (reg->dnsmgr) ? "Y" : "N", 
               reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
      counter++;
   }
   AST_LIST_UNLOCK(&registrations);
   ast_cli(a->fd, "%d IAX2 registrations.\n", counter);
   return CLI_SUCCESS;
#undef FORMAT
#undef FORMAT2
}
static char* handle_cli_iax2_show_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3692 of file chan_iax2.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, ast_cli_args::fd, iax_frame::final, iax_get_frames(), iax_get_iframes(), iax_get_oframes(), iax_frame::retries, trunk_maxmtu, and ast_cli_entry::usage.

{
   struct iax_frame *cur;
   int cnt = 0, dead = 0, final = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show stats";
      e->usage =
         "Usage: iax2 show stats\n"
         "       Display statistics on IAX channel driver.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3)
      return CLI_SHOWUSAGE;

   AST_LIST_LOCK(&frame_queue);
   AST_LIST_TRAVERSE(&frame_queue, cur, list) {
      if (cur->retries < 0)
         dead++;
      if (cur->final)
         final++;
      cnt++;
   }
   AST_LIST_UNLOCK(&frame_queue);

   ast_cli(a->fd, "    IAX Statistics\n");
   ast_cli(a->fd, "---------------------\n");
   ast_cli(a->fd, "Outstanding frames: %d (%d ingress, %d egress)\n", iax_get_frames(), iax_get_iframes(), iax_get_oframes());
   ast_cli(a->fd, "%d timed and %d untimed transmits; MTU %d/%d/%d\n", trunk_timed, trunk_untimed,
      trunk_maxmtu, trunk_nmaxmtu, global_max_trunk_mtu);
   ast_cli(a->fd, "Packets in transmit queue: %d dead, %d final, %d total\n\n", dead, final, cnt);

   trunk_timed = trunk_untimed = 0;
   if (trunk_maxmtu > trunk_nmaxmtu)
      trunk_nmaxmtu = trunk_maxmtu;

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_threads ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6487 of file chan_iax2.c.

References iax2_thread::actions, ast_cli_args::argc, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, iax2_thread::checktime, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, iax2_thread::curfunc, ast_cli_args::fd, IAX_THREAD_TYPE_DYNAMIC, iaxthreadcount, iax2_thread::iostate, thread, iax2_thread::threadnum, iax2_thread::type, type, and ast_cli_entry::usage.

{
   struct iax2_thread *thread = NULL;
   time_t t;
   int threadcount = 0, dynamiccount = 0;
   char type;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show threads";
      e->usage =
         "Usage: iax2 show threads\n"
         "       Lists status of IAX helper threads\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc != 3)
      return CLI_SHOWUSAGE;
      
   ast_cli(a->fd, "IAX2 Thread Information\n");
   time(&t);
   ast_cli(a->fd, "Idle Threads:\n");
   AST_LIST_LOCK(&idle_list);
   AST_LIST_TRAVERSE(&idle_list, thread, list) {
#ifdef DEBUG_SCHED_MULTITHREAD
      ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n", 
         thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
#else
      ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n", 
         thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
#endif
      threadcount++;
   }
   AST_LIST_UNLOCK(&idle_list);
   ast_cli(a->fd, "Active Threads:\n");
   AST_LIST_LOCK(&active_list);
   AST_LIST_TRAVERSE(&active_list, thread, list) {
      if (thread->type == IAX_THREAD_TYPE_DYNAMIC)
         type = 'D';
      else
         type = 'P';
#ifdef DEBUG_SCHED_MULTITHREAD
      ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d, func='%s'\n", 
         type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
#else
      ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d\n", 
         type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
#endif
      threadcount++;
   }
   AST_LIST_UNLOCK(&active_list);
   ast_cli(a->fd, "Dynamic Threads:\n");
   AST_LIST_LOCK(&dynamic_list);
   AST_LIST_TRAVERSE(&dynamic_list, thread, list) {
#ifdef DEBUG_SCHED_MULTITHREAD
      ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n",
         thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
#else
      ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n",
         thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
#endif
      dynamiccount++;
   }
   AST_LIST_UNLOCK(&dynamic_list);
   ast_cli(a->fd, "%d of %d threads accounted for with %d dynamic threads\n", threadcount, iaxthreadcount, dynamiccount);
   return CLI_SUCCESS;
}
static char* handle_cli_iax2_show_users ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6283 of file chan_iax2.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), ast_strlen_zero(), ast_test_flag, iax2_user::authmethods, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, iax2_context::context, iax2_user::contexts, DEFAULT_CONTEXT, ast_cli_args::fd, FORMAT, FORMAT2, iax2_user::ha, IAX_CODEC_NOCAP, IAX_CODEC_NOPREFS, IAX_CODEC_USER_FIRST, iax2_user::inkeys, iax2_user::name, iax2_user::secret, ast_cli_entry::usage, user, and user_unref().

{
   regex_t regexbuf;
   int havepattern = 0;

#define FORMAT "%-15.15s  %-20.20s  %-15.15s  %-15.15s  %-5.5s  %-5.10s\n"
#define FORMAT2 "%-15.15s  %-20.20s  %-15.15d  %-15.15s  %-5.5s  %-5.10s\n"

   struct iax2_user *user = NULL;
   char auth[90];
   char *pstr = "";
   struct ao2_iterator i;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 show users [like]";
      e->usage =
         "Usage: iax2 show users [like <pattern>]\n"
         "       Lists all known IAX2 users.\n"
         "       Optional regular expression pattern is used to filter the user list.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   switch (a->argc) {
   case 5:
      if (!strcasecmp(a->argv[3], "like")) {
         if (regcomp(&regexbuf, a->argv[4], REG_EXTENDED | REG_NOSUB))
            return CLI_SHOWUSAGE;
         havepattern = 1;
      } else
         return CLI_SHOWUSAGE;
   case 3:
      break;
   default:
      return CLI_SHOWUSAGE;
   }

   ast_cli(a->fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
   i = ao2_iterator_init(users, 0);
   for (user = ao2_iterator_next(&i); user; 
      user_unref(user), user = ao2_iterator_next(&i)) {
      if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
         continue;
      
      if (!ast_strlen_zero(user->secret)) {
         ast_copy_string(auth,user->secret, sizeof(auth));
      } else if (!ast_strlen_zero(user->inkeys)) {
         snprintf(auth, sizeof(auth), "Key: %-15.15s ", user->inkeys);
      } else
         ast_copy_string(auth, "-no secret-", sizeof(auth));
      
      if(ast_test_flag(user,IAX_CODEC_NOCAP))
         pstr = "REQ Only";
      else if(ast_test_flag(user,IAX_CODEC_NOPREFS))
         pstr = "Disabled";
      else
         pstr = ast_test_flag(user,IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
      
      ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods, 
         user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
         user->ha ? "Yes" : "No", pstr);
   }
   ao2_iterator_destroy(&i);

   if (havepattern)
      regfree(&regexbuf);

   return CLI_SUCCESS;
#undef FORMAT
#undef FORMAT2
}
static char* handle_cli_iax2_test_losspct ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3476 of file chan_iax2.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 test losspct";
      e->usage =
         "Usage: iax2 test losspct <percentage>\n"
         "       For testing, throws away <percentage> percent of incoming packets\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   if (a->argc != 4)
      return CLI_SHOWUSAGE;

   test_losspct = atoi(a->argv[3]);

   return CLI_SUCCESS;
}
static char* handle_cli_iax2_unregister ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 6556 of file chan_iax2.c.

References ao2_find, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_iax2_unregister(), iax2_peer::expire, expire_registry(), ast_cli_args::fd, find_peer(), ast_cli_args::line, ast_cli_args::n, iax2_peer::name, OBJ_POINTER, peer_ref(), peer_unref(), ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   struct iax2_peer *p;

   switch (cmd) {
   case CLI_INIT:
      e->command = "iax2 unregister";
      e->usage =
         "Usage: iax2 unregister <peername>\n"
         "       Unregister (force expiration) an IAX2 peer from the registry.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_iax2_unregister(a->line, a->word, a->pos, a->n);
   }

   if (a->argc != 3)
      return CLI_SHOWUSAGE;

   p = find_peer(a->argv[2], 1);
   if (p) {
      if (p->expire > 0) {
         struct iax2_peer tmp_peer = {
            .name = a->argv[2],
         };
         struct iax2_peer *peer;

         peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
         if (peer) {
            expire_registry(peer_ref(peer)); /* will release its own reference when done */
            peer_unref(peer); /* ref from ao2_find() */
            ast_cli(a->fd, "Peer %s unregistered\n", a->argv[2]);
         } else {
            ast_cli(a->fd, "Peer %s not found\n", a->argv[2]);
         }
      } else {
         ast_cli(a->fd, "Peer %s not registered\n", a->argv[2]);
      }
   } else {
      ast_cli(a->fd, "Peer unknown: %s. Not unregistered\n", a->argv[2]);
   }
   return CLI_SUCCESS;
}
static void handle_deferred_full_frames ( struct iax2_thread thread) [static]

Handle any deferred full frames for this thread.

Definition at line 9158 of file chan_iax2.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), iax2_pkt_buf::buf, iax2_thread::buf, iax2_thread::buf_len, iax2_thread::buf_size, iax2_thread::full_frames, iax2_pkt_buf::len, iax2_thread::lock, and socket_process().

Referenced by iax2_process_thread().

{
   struct iax2_pkt_buf *pkt_buf;

   ast_mutex_lock(&thread->lock);

   while ((pkt_buf = AST_LIST_REMOVE_HEAD(&thread->full_frames, entry))) {
      ast_mutex_unlock(&thread->lock);

      thread->buf = pkt_buf->buf;
      thread->buf_len = pkt_buf->len;
      thread->buf_size = pkt_buf->len + 1;
      
      socket_process(thread);

      thread->buf = NULL;
      ast_free(pkt_buf);

      ast_mutex_lock(&thread->lock);
   }

   ast_mutex_unlock(&thread->lock);
}
static int handle_error ( void  ) [static]

Definition at line 3130 of file chan_iax2.c.

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

Referenced by send_packet(), socket_read(), and transmit_trunk().

{
   /* XXX Ideally we should figure out why an error occurred and then abort those
      rather than continuing to try.  Unfortunately, the published interface does
      not seem to work XXX */
#if 0
   struct sockaddr_in *sin;
   int res;
   struct msghdr m;
   struct sock_extended_err e;
   m.msg_name = NULL;
   m.msg_namelen = 0;
   m.msg_iov = NULL;
   m.msg_control = &e;
   m.msg_controllen = sizeof(e);
   m.msg_flags = 0;
   res = recvmsg(netsocket, &m, MSG_ERRQUEUE);
   if (res < 0)
      ast_log(LOG_WARNING, "Error detected, but unable to read error: %s\n", strerror(errno));
   else {
      if (m.msg_controllen) {
         sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);
         if (sin) 
            ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(sin->sin_addr));
         else
            ast_log(LOG_WARNING, "No address detected??\n");
      } else {
         ast_log(LOG_WARNING, "Local error: %s\n", strerror(e.ee_errno));
      }
   }
#endif
   return 0;
}
static int iax2_ack_registry ( struct iax_ies ies,
struct sockaddr_in *  sin,
int  callno 
) [static]

Acknowledgment received for OUR registration.

Definition at line 8125 of file chan_iax2.c.

References iax2_registry::addr, iax_ies::apparent_addr, ast_copy_string(), ast_inet_ntoa(), ast_log(), ast_verb, iax_ies::calling_number, EVENT_FLAG_SYSTEM, iax2_registry::expire, iax2_do_register_s(), iax2_sched_replace(), inaddrcmp(), LOG_WARNING, manager_event, iax2_registry::messages, iax_ies::msgcount, iax_ies::refresh, iax2_registry::refresh, chan_iax2_pvt::reg, REG_STATE_REGISTERED, iax2_registry::regstate, iax2_registry::us, and iax_ies::username.

Referenced by socket_process().

{
   struct iax2_registry *reg;
   /* Start pessimistic */
   char peer[256] = "";
   char msgstatus[60];
   int refresh = 60;
   char ourip[256] = "<Unspecified>";
   struct sockaddr_in oldus;
   struct sockaddr_in us;
   int oldmsgs;

   memset(&us, 0, sizeof(us));
   if (ies->apparent_addr)
      memmove(&us, ies->apparent_addr, sizeof(us));
   if (ies->username)
      ast_copy_string(peer, ies->username, sizeof(peer));
   if (ies->refresh)
      refresh = ies->refresh;
   if (ies->calling_number) {
      /* We don't do anything with it really, but maybe we should */
   }
   reg = iaxs[callno]->reg;
   if (!reg) {
      ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
      return -1;
   }
   memcpy(&oldus, &reg->us, sizeof(oldus));
   oldmsgs = reg->messages;
   if (inaddrcmp(&reg->addr, sin)) {
      ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(sin->sin_addr));
      return -1;
   }
   memcpy(&reg->us, &us, sizeof(reg->us));
   if (ies->msgcount >= 0)
      reg->messages = ies->msgcount & 0xffff;      /* only low 16 bits are used in the transmission of the IE */
   /* always refresh the registration at the interval requested by the server
      we are registering to
   */
   reg->refresh = refresh;
   reg->expire = iax2_sched_replace(reg->expire, sched, 
      (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
   if (inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
         if (reg->messages > 255)
            snprintf(msgstatus, sizeof(msgstatus), " with %d new and %d old messages waiting", reg->messages & 0xff, reg->messages >> 8);
         else if (reg->messages > 1)
            snprintf(msgstatus, sizeof(msgstatus), " with %d new messages waiting\n", reg->messages);
         else if (reg->messages > 0)
            ast_copy_string(msgstatus, " with 1 new message waiting\n", sizeof(msgstatus));
         else
            ast_copy_string(msgstatus, " with no messages waiting\n", sizeof(msgstatus));
         snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
      ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(sin->sin_addr), ourip, msgstatus);
      manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", ast_inet_ntoa(sin->sin_addr));
   }
   reg->regstate = REG_STATE_REGISTERED;
   return 0;
}
static int attribute_pure iax2_allow_new ( int  frametype,
int  subclass,
int  inbound 
) [inline, static]

Definition at line 2594 of file chan_iax2.c.

References AST_FRAME_IAX, IAX_COMMAND_FWDOWNL, IAX_COMMAND_NEW, IAX_COMMAND_POKE, IAX_COMMAND_REGREL, and IAX_COMMAND_REGREQ.

Referenced by resend_with_token(), and socket_process().

{
   if (frametype != AST_FRAME_IAX) {
      return 0;
   }
   switch (subclass) {
   case IAX_COMMAND_NEW:
   case IAX_COMMAND_REGREQ:
   case IAX_COMMAND_FWDOWNL:
   case IAX_COMMAND_REGREL:
      return 1;
   case IAX_COMMAND_POKE:
      if (!inbound) {
         return 1;
      }
      break;
   }
   return 0;
}
static void iax2_ami_channelupdate ( struct chan_iax2_pvt pvt) [static]

Send manager event at call setup to link between Asterisk channel name and IAX2 call identifiers.

Definition at line 1226 of file chan_iax2.c.

References chan_iax2_pvt::callno, EVENT_FLAG_SYSTEM, manager_event, ast_channel::name, chan_iax2_pvt::owner, chan_iax2_pvt::peer, and chan_iax2_pvt::peercallno.

Referenced by ast_iax2_new(), and iax2_answer().

{
   manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
      "Channel: %s\r\nChanneltype: IAX2\r\nIAX2-callno-local: %d\r\nIAX2-callno-remote: %d\r\nIAX2-peer: %s\r\n",
      pvt->owner ? pvt->owner->name : "",
      pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
}
static int iax2_answer ( struct ast_channel c) [static]

Definition at line 5358 of file chan_iax2.c.

References AST_CONTROL_ANSWER, ast_debug, AST_FRAME_CONTROL, ast_mutex_lock(), ast_mutex_unlock(), iax2_ami_channelupdate(), PTR_TO_CALLNO, send_command_locked(), and ast_channel::tech_pvt.

{
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   ast_debug(1, "Answering IAX2 call\n");
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno])
      iax2_ami_channelupdate(iaxs[callno]);
   ast_mutex_unlock(&iaxsl[callno]);
   return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
}
static int iax2_append_register ( const char *  hostname,
const char *  username,
const char *  secret,
const char *  porta 
) [static]

Definition at line 8184 of file chan_iax2.c.

References iax2_registry::addr, ast_calloc, ast_copy_string(), ast_dnsmgr_lookup(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, iax2_registry::dnsmgr, iax2_registry::expire, IAX_DEFAULT_PORTNO, IAX_DEFAULT_REG_EXPIRE, iax2_registry::refresh, iax2_registry::secret, and iax2_registry::username.

Referenced by iax2_register().

{
   struct iax2_registry *reg;

   if (!(reg = ast_calloc(1, sizeof(*reg))))
      return -1;

   if (ast_dnsmgr_lookup(hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) {
      ast_free(reg);
      return -1;
   }

   ast_copy_string(reg->username, username, sizeof(reg->username));

   if (secret)
      ast_copy_string(reg->secret, secret, sizeof(reg->secret));

   reg->expire = -1;
   reg->refresh = IAX_DEFAULT_REG_EXPIRE;
   reg->addr.sin_family = AF_INET;
   reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(IAX_DEFAULT_PORTNO);

   AST_LIST_LOCK(&registrations);
   AST_LIST_INSERT_HEAD(&registrations, reg, entry);
   AST_LIST_UNLOCK(&registrations);
   
   return 0;
}
static enum ast_bridge_result iax2_bridge ( struct ast_channel c0,
struct ast_channel c1,
int  flags,
struct ast_frame **  fo,
struct ast_channel **  rc,
int  timeoutms 
) [static]

Definition at line 5203 of file chan_iax2.c.

References ast_channel::_softhangup, AST_BRIDGE_COMPLETE, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_FAILED_NOWARN, AST_BRIDGE_IGNORE_SIGS, AST_BRIDGE_RETRY, ast_check_hangup(), AST_CONTROL_SRCUPDATE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_getformatname_multiple(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), AST_SOFTHANGUP_DEV, ast_test_flag, ast_tvnow(), ast_tvzero(), ast_verb, ast_waitfor_n(), ast_write(), chan_iax2_pvt::bridgecallno, f, ast_frame::frametype, iax2_start_transfer(), IAX_LINGER_TIMEOUT, IAX_NOTRANSFER, IAX_TRANSFERMEDIA, lock_both(), LOG_WARNING, ast_channel::nativeformats, PTR_TO_CALLNO, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, TRANSFER_RELEASED, and unlock_both().

{
   struct ast_channel *cs[3];
   struct ast_channel *who, *other;
   int to = -1;
   int res = -1;
   int transferstarted=0;
   struct ast_frame *f;
   unsigned short callno0 = PTR_TO_CALLNO(c0->tech_pvt);
   unsigned short callno1 = PTR_TO_CALLNO(c1->tech_pvt);
   struct timeval waittimer = {0, 0};

   /* We currently do not support native bridging if a timeoutms value has been provided */
   if (timeoutms > 0) {
      return AST_BRIDGE_FAILED;
   }

   timeoutms = -1;

   lock_both(callno0, callno1);
   if (!iaxs[callno0] || !iaxs[callno1]) {
      unlock_both(callno0, callno1);
      return AST_BRIDGE_FAILED;
   }
   /* Put them in native bridge mode */
   if (!(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
      iaxs[callno0]->bridgecallno = callno1;
      iaxs[callno1]->bridgecallno = callno0;
   }
   unlock_both(callno0, callno1);

   /* If not, try to bridge until we can execute a transfer, if we can */
   cs[0] = c0;
   cs[1] = c1;
   for (/* ever */;;) {
      /* Check in case we got masqueraded into */
      if ((c0->tech != &iax2_tech) || (c1->tech != &iax2_tech)) {
         ast_verb(3, "Can't masquerade, we're different...\n");
         /* Remove from native mode */
         if (c0->tech == &iax2_tech) {
            ast_mutex_lock(&iaxsl[callno0]);
            iaxs[callno0]->bridgecallno = 0;
            ast_mutex_unlock(&iaxsl[callno0]);
         }
         if (c1->tech == &iax2_tech) {
            ast_mutex_lock(&iaxsl[callno1]);
            iaxs[callno1]->bridgecallno = 0;
            ast_mutex_unlock(&iaxsl[callno1]);
         }
         return AST_BRIDGE_FAILED_NOWARN;
      }
      if (c0->nativeformats != c1->nativeformats) {
            char buf0[255];
            char buf1[255];
            ast_getformatname_multiple(buf0, sizeof(buf0) -1, c0->nativeformats);
            ast_getformatname_multiple(buf1, sizeof(buf1) -1, c1->nativeformats);
         ast_verb(3, "Operating with different codecs %d[%s] %d[%s] , can't native bridge...\n", c0->nativeformats, buf0, c1->nativeformats, buf1);
         /* Remove from native mode */
         lock_both(callno0, callno1);
         if (iaxs[callno0])
            iaxs[callno0]->bridgecallno = 0;
         if (iaxs[callno1])
            iaxs[callno1]->bridgecallno = 0;
         unlock_both(callno0, callno1);
         return AST_BRIDGE_FAILED_NOWARN;
      }
      /* check if transfered and if we really want native bridging */
      if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) {
         /* Try the transfer */
         if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
                     ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA)))
            ast_log(LOG_WARNING, "Unable to start the transfer\n");
         transferstarted = 1;
      }
      if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
         /* Call has been transferred.  We're no longer involved */
         struct timeval now = ast_tvnow();
         if (ast_tvzero(waittimer)) {
            waittimer = now;
         } else if (now.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
            c0->_softhangup |= AST_SOFTHANGUP_DEV;
            c1->_softhangup |= AST_SOFTHANGUP_DEV;
            *fo = NULL;
            *rc = c0;
            res = AST_BRIDGE_COMPLETE;
            break;
         }
      }
      to = 1000;
      who = ast_waitfor_n(cs, 2, &to);
      if (timeoutms > -1) {
         timeoutms -= (1000 - to);
         if (timeoutms < 0)
            timeoutms = 0;
      }
      if (!who) {
         if (!timeoutms) {
            res = AST_BRIDGE_RETRY;
            break;
         }
         if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
            res = AST_BRIDGE_FAILED;
            break;
         }
         continue;
      }
      f = ast_read(who);
      if (!f) {
         *fo = NULL;
         *rc = who;
         res = AST_BRIDGE_COMPLETE;
         break;
      }
      if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS) && (f->subclass != AST_CONTROL_SRCUPDATE)) {
         *fo = f;
         *rc = who;
         res =  AST_BRIDGE_COMPLETE;
         break;
      }
      other = (who == c0) ? c1 : c0;  /* the 'other' channel */
      if ((f->frametype == AST_FRAME_VOICE) ||
         (f->frametype == AST_FRAME_TEXT) ||
         (f->frametype == AST_FRAME_VIDEO) || 
         (f->frametype == AST_FRAME_IMAGE) ||
         (f->frametype == AST_FRAME_DTMF) ||
         (f->frametype == AST_FRAME_CONTROL)) {
         /* monitored dtmf take out of the bridge.
          * check if we monitor the specific source.
          */
         int monitored_source = (who == c0) ? AST_BRIDGE_DTMF_CHANNEL_0 : AST_BRIDGE_DTMF_CHANNEL_1;
         if (f->frametype == AST_FRAME_DTMF && (flags & monitored_source)) {
            *rc = who;
            *fo = f;
            res = AST_BRIDGE_COMPLETE;
            /* Remove from native mode */
            break;
         }
         /* everything else goes to the other side */
         ast_write(other, f);
      }
      ast_frfree(f);
      /* Swap who gets priority */
      cs[2] = cs[0];
      cs[0] = cs[1];
      cs[1] = cs[2];
   }
   lock_both(callno0, callno1);
   if(iaxs[callno0])
      iaxs[callno0]->bridgecallno = 0;
   if(iaxs[callno1])
      iaxs[callno1]->bridgecallno = 0;
   unlock_both(callno0, callno1);
   return res;
}
static int iax2_call ( struct ast_channel c,
char *  dest,
int  timeout 
) [static]

Definition at line 4810 of file chan_iax2.c.

References ast_channel::_state, add_empty_calltoken_ie(), create_addr_info::adsi, chan_iax2_pvt::adsi, ast_channel::adsicpe, ast_channel_datastore_find(), ast_copy_string(), ast_debug, AST_FRAME_IAX, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PRES_NUMBER_NOT_AVAILABLE, ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_var_name(), ast_var_value(), auto_congest(), iax_ie_data::buf, CALLNO_TO_PTR, capability, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, context, create_addr_info::context, ast_channel::context, parsed_dial_string::context, create_addr(), ast_datastore::data, chan_iax2_pvt::encmethods, create_addr_info::encmethods, parsed_dial_string::exten, iax2_datetime(), iax2_encryption, iax2_sched_add(), IAX_COMMAND_NEW, IAX_FORCE_ENCRYPT, IAX_IE_ADSICPE, iax_ie_append(), iax_ie_append_byte(), iax_ie_append_int(), iax_ie_append_raw(), iax_ie_append_short(), iax_ie_append_str(), IAX_IE_AUTOANSWER, IAX_IE_CALLED_CONTEXT, IAX_IE_CALLED_NUMBER, IAX_IE_CALLING_ANI, IAX_IE_CALLING_NAME, IAX_IE_CALLING_NUMBER, IAX_IE_CALLINGPRES, IAX_IE_CALLINGTNS, IAX_IE_CALLINGTON, IAX_IE_CAPABILITY, IAX_IE_CODEC_PREFS, IAX_IE_DATETIME, IAX_IE_DNID, IAX_IE_ENCRYPTION, IAX_IE_FORMAT, IAX_IE_LANGUAGE, IAX_IE_OSPTOKEN, IAX_IE_RDNIS, IAX_IE_USERNAME, IAX_IE_VARIABLE, IAX_IE_VERSION, IAX_MAX_OSPBLOCK_SIZE, IAX_MAX_OSPTOKEN_SIZE, IAX_PROTO_VERSION, IAX_SENDANI, chan_iax2_pvt::initid, parsed_dial_string::key, ast_channel::language, LOG_WARNING, chan_iax2_pvt::maxtime, create_addr_info::mohinterpret, create_addr_info::mohsuggest, ast_channel::name, ast_channel::nativeformats, parsed_dial_string::options, create_addr_info::outkey, parse_dial_string(), parsed_dial_string::password, pbx_builtin_getvar_helper(), parsed_dial_string::peer, create_addr_info::peercontext, chan_iax2_pvt::pingtime, parsed_dial_string::port, iax_ie_data::pos, create_addr_info::prefs, PTR_TO_CALLNO, secret, create_addr_info::secret, send_command(), create_addr_info::sockfd, chan_iax2_pvt::sockfd, ast_channel::tech_pvt, create_addr_info::timezone, create_addr_info::username, parsed_dial_string::username, and var.

{
   struct sockaddr_in sin;
   char *l=NULL, *n=NULL, *tmpstr;
   struct iax_ie_data ied;
   char *defaultrdest = "s";
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   struct parsed_dial_string pds;
   struct create_addr_info cai;
   struct ast_var_t *var;
   struct ast_datastore *variablestore = ast_channel_datastore_find(c, &iax2_variable_datastore_info, NULL);
   const char* osp_token_ptr;
   unsigned int osp_token_length;
   unsigned char osp_block_index;
   unsigned int osp_block_length;
   unsigned char osp_buffer[256];

   if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
      ast_log(LOG_WARNING, "Channel is already in use (%s)?\n", c->name);
      return -1;
   }

   memset(&cai, 0, sizeof(cai));
   cai.encmethods = iax2_encryption;

   memset(&pds, 0, sizeof(pds));
   tmpstr = ast_strdupa(dest);
   parse_dial_string(tmpstr, &pds);

   if (ast_strlen_zero(pds.peer)) {
      ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", dest);
      return -1;
   }
   if (!pds.exten) {
      pds.exten = defaultrdest;
   }
   if (create_addr(pds.peer, c, &sin, &cai)) {
      ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer);
      return -1;
   }
   if (ast_strlen_zero(cai.secret) && ast_test_flag(iaxs[callno], IAX_FORCE_ENCRYPT)) {
      ast_log(LOG_WARNING, "Call terminated. No secret given and force encrypt enabled\n");
      return -1;
   }
   if (!pds.username && !ast_strlen_zero(cai.username))
      pds.username = cai.username;
   if (!pds.password && !ast_strlen_zero(cai.secret))
      pds.password = cai.secret;
   if (!pds.key && !ast_strlen_zero(cai.outkey))
      pds.key = cai.outkey;
   if (!pds.context && !ast_strlen_zero(cai.peercontext))
      pds.context = cai.peercontext;

   /* Keep track of the context for outgoing calls too */
   ast_copy_string(c->context, cai.context, sizeof(c->context));

   if (pds.port)
      sin.sin_port = htons(atoi(pds.port));

   l = c->cid.cid_num;
   n = c->cid.cid_name;

   /* Now build request */ 
   memset(&ied, 0, sizeof(ied));

   /* On new call, first IE MUST be IAX version of caller */
   iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
   iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, pds.exten);
   if (pds.options && strchr(pds.options, 'a')) {
      /* Request auto answer */
      iax_ie_append(&ied, IAX_IE_AUTOANSWER);
   }

   iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);

   if (l) {
      iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
      iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
   } else {
      if (n)
         iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
      else
         iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE);
   }

   iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton);
   iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns);

   if (n)
      iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, n);
   if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani)
      iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani);

   if (!ast_strlen_zero(c->language))
      iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language);
   if (!ast_strlen_zero(c->cid.cid_dnid))
      iax_ie_append_str(&ied, IAX_IE_DNID, c->cid.cid_dnid);
   if (!ast_strlen_zero(c->cid.cid_rdnis))
      iax_ie_append_str(&ied, IAX_IE_RDNIS, c->cid.cid_rdnis);

   if (pds.context)
      iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, pds.context);

   if (pds.username)
      iax_ie_append_str(&ied, IAX_IE_USERNAME, pds.username);

   if (cai.encmethods)
      iax_ie_append_short(&ied, IAX_IE_ENCRYPTION, cai.encmethods);

   ast_mutex_lock(&iaxsl[callno]);

   if (!ast_strlen_zero(c->context))
      ast_string_field_set(iaxs[callno], context, c->context);

   if (pds.username)
      ast_string_field_set(iaxs[callno], username, pds.username);

   iaxs[callno]->encmethods = cai.encmethods;

   iaxs[callno]->adsi = cai.adsi;
   
   ast_string_field_set(iaxs[callno], mohinterpret, cai.mohinterpret);
   ast_string_field_set(iaxs[callno], mohsuggest, cai.mohsuggest);

   if (pds.key)
      ast_string_field_set(iaxs[callno], outkey, pds.key);
   if (pds.password)
      ast_string_field_set(iaxs[callno], secret, pds.password);

   iax_ie_append_int(&ied, IAX_IE_FORMAT, c->nativeformats);
   iax_ie_append_int(&ied, IAX_IE_CAPABILITY, iaxs[callno]->capability);
   iax_ie_append_short(&ied, IAX_IE_ADSICPE, c->adsicpe);
   iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(cai.timezone));

   if (iaxs[callno]->maxtime) {
      /* Initialize pingtime and auto-congest time */
      iaxs[callno]->pingtime = iaxs[callno]->maxtime / 2;
      iaxs[callno]->initid = iax2_sched_add(sched, iaxs[callno]->maxtime * 2, auto_congest, CALLNO_TO_PTR(callno));
   } else if (autokill) {
      iaxs[callno]->pingtime = autokill / 2;
      iaxs[callno]->initid = iax2_sched_add(sched, autokill * 2, auto_congest, CALLNO_TO_PTR(callno));
   }

   /* Check if there is an OSP token */
   osp_token_ptr = pbx_builtin_getvar_helper(c, "IAX2OSPTOKEN");
   if (!ast_strlen_zero(osp_token_ptr)) {
      if ((osp_token_length = strlen(osp_token_ptr)) <= IAX_MAX_OSPTOKEN_SIZE) {
         osp_block_index = 0;
         while (osp_token_length > 0) {
            osp_block_length = IAX_MAX_OSPBLOCK_SIZE < osp_token_length ? IAX_MAX_OSPBLOCK_SIZE : osp_token_length;
            osp_buffer[0] = osp_block_index;
            memcpy(osp_buffer + 1, osp_token_ptr, osp_block_length);
            iax_ie_append_raw(&ied, IAX_IE_OSPTOKEN, osp_buffer, osp_block_length + 1);
            osp_block_index++;
            osp_token_ptr += osp_block_length;
            osp_token_length -= osp_block_length;
         } 
      } else
         ast_log(LOG_WARNING, "OSP token is too long\n");
   } else if (iaxdebug)
      ast_debug(1, "OSP token is undefined\n");

   /* send the command using the appropriate socket for this peer */
   iaxs[callno]->sockfd = cai.sockfd;

   /* Add remote vars */
   if (variablestore) {
      AST_LIST_HEAD(, ast_var_t) *variablelist = variablestore->data;
      ast_debug(1, "Found an IAX variable store on this channel\n");
      AST_LIST_LOCK(variablelist);
      AST_LIST_TRAVERSE(variablelist, var, entries) {
         char tmp[256];
         int i;
         ast_debug(1, "Found IAXVAR '%s' with value '%s' (to transmit)\n", ast_var_name(var), ast_var_value(var));
         /* Automatically divide the value up into sized chunks */
         for (i = 0; i < strlen(ast_var_value(var)); i += 255 - (strlen(ast_var_name(var)) + 1)) {
            snprintf(tmp, sizeof(tmp), "%s=%s", ast_var_name(var), ast_var_value(var) + i);
            iax_ie_append_str(&ied, IAX_IE_VARIABLE, tmp);
         }
      }
      AST_LIST_UNLOCK(variablelist);
   }

   /* Transmit the string in a "NEW" request */
   add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
   send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);

   ast_mutex_unlock(&iaxsl[callno]);
   ast_setstate(c, AST_STATE_RINGING);

   return 0;
}
static int iax2_canmatch ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data 
) [static]

part of the IAX2 dial plan switch interface

Definition at line 13280 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), CACHE_FLAG_CANEXIST, find_cache(), iax2_dpcache::flags, LOG_NOTICE, and LOG_WARNING.

{
   int res = 0;
   struct iax2_dpcache *dp = NULL;
#if 0
   ast_log(LOG_NOTICE, "iax2_canmatch: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
#endif
   if ((priority != 1) && (priority != 2))
      return 0;

   AST_LIST_LOCK(&dpcache);
   if ((dp = find_cache(chan, data, context, exten, priority))) {
      if (dp->flags & CACHE_FLAG_CANEXIST)
         res = 1;
   } else {
      ast_log(LOG_WARNING, "Unable to make DP cache\n");
   }
   AST_LIST_UNLOCK(&dpcache);

   return res;
}
static unsigned int iax2_datetime ( const char *  tz) [static]

Definition at line 4481 of file chan_iax2.c.

References ast_localtime(), ast_strlen_zero(), ast_tvnow(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.

Referenced by iax2_call(), and update_registry().

{
   struct timeval t = ast_tvnow();
   struct ast_tm tm;
   unsigned int tmp;
   ast_localtime(&t, &tm, ast_strlen_zero(tz) ? NULL : tz);
   tmp  = (tm.tm_sec >> 1) & 0x1f;        /* 5 bits of seconds */
   tmp |= (tm.tm_min & 0x3f) << 5;        /* 6 bits of minutes */
   tmp |= (tm.tm_hour & 0x1f) << 11;      /* 5 bits of hours */
   tmp |= (tm.tm_mday & 0x1f) << 16;      /* 5 bits of day of month */
   tmp |= ((tm.tm_mon + 1) & 0xf) << 21;     /* 4 bits of month */
   tmp |= ((tm.tm_year - 100) & 0x7f) << 25; /* 7 bits of year */
   return tmp;
}
static void iax2_destroy ( int  callno) [static]

Definition at line 3236 of file chan_iax2.c.

References ao2_ref, ast_channel_trylock, ast_channel_unlock, ast_debug, ast_queue_hangup(), DEADLOCK_AVOIDANCE, iax2_destroy_helper(), chan_iax2_pvt::owner, chan_iax2_pvt::peercallno, remove_by_peercallno(), remove_by_transfercallno(), chan_iax2_pvt::transfercallno, and update_max_trunk().

Referenced by __attempt_transmit(), __iax2_poke_noanswer(), __unload_module(), delete_users(), iax2_do_register(), iax2_hangup(), iax2_poke_peer(), peer_destructor(), scheduled_destroy(), and socket_process().

{
   struct chan_iax2_pvt *pvt = NULL;
   struct ast_channel *owner = NULL;

retry:
   if ((pvt = iaxs[callno])) {
#if 0
      /* iax2_destroy_helper gets called from this function later on.  When
       * called twice, we get the (previously) familiar FRACK! errors in
       * devmode, from the scheduler.  An alternative to this approach is to
       * reset the scheduler entries to -1 when they're deleted in
       * iax2_destroy_helper().  That approach was previously decided to be
       * "wrong" because "the memory is going to be deallocated anyway.  Why
       * should we be resetting those values?" */
      iax2_destroy_helper(pvt);
#endif
   }

   owner = pvt ? pvt->owner : NULL;

   if (owner) {
      if (ast_channel_trylock(owner)) {
         ast_debug(3, "Avoiding IAX destroy deadlock\n");
         DEADLOCK_AVOIDANCE(&iaxsl[callno]);
         goto retry;
      }
   }

   if (!owner) {
      iaxs[callno] = NULL;
   }

   if (pvt) {
      if (!owner) {
         pvt->owner = NULL;
      } else {
         /* If there's an owner, prod it to give up */
         /* It is ok to use ast_queue_hangup() here instead of iax2_queue_hangup()
          * because we already hold the owner channel lock. */
         ast_queue_hangup(owner);
      }

      if (pvt->peercallno) {
         remove_by_peercallno(pvt);
      }

      if (pvt->transfercallno) {
         remove_by_transfercallno(pvt);
      }

      if (!owner) {
         ao2_ref(pvt, -1);
         pvt = NULL;
      }
   }

   if (owner) {
      ast_channel_unlock(owner);
   }

   if (callno & 0x4000) {
      update_max_trunk();
   }
}
static void iax2_destroy_helper ( struct chan_iax2_pvt pvt) [static]
static int iax2_devicestate ( void *  data) [static]

Part of the device state notification system ---.

Definition at line 13483 of file chan_iax2.c.

References iax2_peer::addr, ast_debug, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), ast_strdupa, ast_strlen_zero(), iax2_peer::defaddr, find_peer(), iax2_peer::historicms, iax2_peer::lastms, LOG_WARNING, iax2_peer::maxms, parse_dial_string(), parsed_dial_string::peer, and peer_unref().

{
   struct parsed_dial_string pds;
   char *tmp = ast_strdupa(data);
   struct iax2_peer *p;
   int res = AST_DEVICE_INVALID;

   memset(&pds, 0, sizeof(pds));
   parse_dial_string(tmp, &pds);

   if (ast_strlen_zero(pds.peer)) {
      ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", (char *) data);
      return res;
   }
   
   ast_debug(3, "Checking device state for device %s\n", pds.peer);

   /* SLD: FIXME: second call to find_peer during registration */
   if (!(p = find_peer(pds.peer, 1)))
      return res;

   res = AST_DEVICE_UNAVAILABLE;
   ast_debug(3, "iax2_devicestate: Found peer. What's device state of %s? addr=%d, defaddr=%d maxms=%d, lastms=%d\n",
      pds.peer, p->addr.sin_addr.s_addr, p->defaddr.sin_addr.s_addr, p->maxms, p->lastms);
   
   if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
       (!p->maxms || ((p->lastms > -1) && (p->historicms <= p->maxms)))) {
      /* Peer is registered, or have default IP address
         and a valid registration */
      if (p->historicms == 0 || p->historicms <= p->maxms)
         /* let the core figure out whether it is in use or not */
         res = AST_DEVICE_UNKNOWN;  
   }

   peer_unref(p);

   return res;
}
static int iax2_digit_begin ( struct ast_channel c,
char  digit 
) [static]
static int iax2_digit_end ( struct ast_channel c,
char  digit,
unsigned int  duration 
) [static]

Definition at line 4110 of file chan_iax2.c.

References AST_FRAME_DTMF_END, PTR_TO_CALLNO, send_command_locked(), and ast_channel::tech_pvt.

{
   return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
}
static int iax2_do_register ( struct iax2_registry reg) [static]

Definition at line 11311 of file chan_iax2.c.

References add_empty_calltoken_ie(), iax2_registry::addr, ast_debug, ast_dnsmgr_changed(), ast_dnsmgr_refresh(), AST_FRAME_IAX, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), iax_ie_data::buf, iax2_registry::callno, iax2_registry::dnsmgr, iax2_registry::expire, find_callno_locked(), iax2_destroy(), iax2_do_register_s(), iax2_sched_replace(), IAX_COMMAND_REGREQ, iax_ie_append_short(), iax_ie_append_str(), IAX_IE_REFRESH, IAX_IE_USERNAME, LOG_WARNING, NEW_FORCE, iax_ie_data::pos, iax2_registry::refresh, chan_iax2_pvt::reg, REG_STATE_REGSENT, REG_STATE_TIMEOUT, iax2_registry::regstate, send_command(), and iax2_registry::username.

Referenced by __iax2_do_register_s(), load_module(), and reload_config().

{
   struct iax_ie_data ied;
   if (iaxdebug)
      ast_debug(1, "Sending registration request for '%s'\n", reg->username);

   if (reg->dnsmgr && 
       ((reg->regstate == REG_STATE_TIMEOUT) || !reg->addr.sin_addr.s_addr)) {
      /* Maybe the IP has changed, force DNS refresh */
      ast_dnsmgr_refresh(reg->dnsmgr);
   }
   
   /*
    * if IP has Changed, free allocated call to create a new one with new IP
    * call has the pointer to IP and must be updated to the new one
    */
   if (reg->dnsmgr && ast_dnsmgr_changed(reg->dnsmgr) && (reg->callno > 0)) {
      int callno = reg->callno;
      ast_mutex_lock(&iaxsl[callno]);
      iax2_destroy(callno);
      ast_mutex_unlock(&iaxsl[callno]);
      reg->callno = 0;
   }
   if (!reg->addr.sin_addr.s_addr) {
      if (iaxdebug)
         ast_debug(1, "Unable to send registration request for '%s' without IP address\n", reg->username);
      /* Setup the next registration attempt */
      reg->expire = iax2_sched_replace(reg->expire, sched, 
         (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
      return -1;
   }

   if (!reg->callno) {
      ast_debug(3, "Allocate call number\n");
      reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
      if (reg->callno < 1) {
         ast_log(LOG_WARNING, "Unable to create call for registration\n");
         return -1;
      } else
         ast_debug(3, "Registration created on call %d\n", reg->callno);
      iaxs[reg->callno]->reg = reg;
      ast_mutex_unlock(&iaxsl[reg->callno]);
   }
   /* Setup the next registration a little early */
   reg->expire = iax2_sched_replace(reg->expire, sched, 
      (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
   /* Send the request */
   memset(&ied, 0, sizeof(ied));
   iax_ie_append_str(&ied, IAX_IE_USERNAME, reg->username);
   iax_ie_append_short(&ied, IAX_IE_REFRESH, reg->refresh);
   add_empty_calltoken_ie(iaxs[reg->callno], &ied); /* this _MUST_ be the last ie added */
   send_command(iaxs[reg->callno],AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
   reg->regstate = REG_STATE_REGSENT;
   return 0;
}
static int iax2_do_register_s ( const void *  data) [static]

Definition at line 7969 of file chan_iax2.c.

References __iax2_do_register_s(), and schedule_action.

Referenced by iax2_ack_registry(), and iax2_do_register().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__iax2_do_register_s, data))
#endif      
      __iax2_do_register_s(data);
   return 0;
}
static void iax2_dprequest ( struct iax2_dpcache dp,
int  callno 
) [static]

Definition at line 8719 of file chan_iax2.c.

References AST_FRAME_IAX, auto_hangup(), chan_iax2_pvt::autoid, iax_ie_data::buf, CACHE_FLAG_TRANSMITTED, iax2_dpcache::exten, iax2_dpcache::flags, iax2_sched_replace(), IAX_COMMAND_DPREQ, iax_ie_append_str(), IAX_IE_CALLED_NUMBER, iax_ie_data::pos, and send_command().

Referenced by find_cache(), and socket_process().

{
   struct iax_ie_data ied;
   /* Auto-hangup with 30 seconds of inactivity */
   iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
      sched, 30000, auto_hangup, (void *)(long)callno);
   memset(&ied, 0, sizeof(ied));
   iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, dp->exten);
   send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
   dp->flags |= CACHE_FLAG_TRANSMITTED;
}
static void * iax2_dup_variable_datastore ( void *  old) [static]

Definition at line 1241 of file chan_iax2.c.

References ast_calloc, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_var_assign(), ast_var_name(), ast_var_value(), ast_var_t::entries, and LOG_ERROR.

{
   AST_LIST_HEAD(, ast_var_t) *oldlist = old, *newlist;
   struct ast_var_t *oldvar, *newvar;

   newlist = ast_calloc(sizeof(*newlist), 1);
   if (!newlist) {
      ast_log(LOG_ERROR, "Unable to duplicate iax2 variables\n");
      return NULL;
   }

   AST_LIST_HEAD_INIT(newlist);
   AST_LIST_LOCK(oldlist);
   AST_LIST_TRAVERSE(oldlist, oldvar, entries) {
      newvar = ast_var_assign(ast_var_name(oldvar), ast_var_value(oldvar));
      if (newvar)
         AST_LIST_INSERT_TAIL(newlist, newvar, entries);
      else
         ast_log(LOG_ERROR, "Unable to duplicate iax2 variable '%s'\n", ast_var_name(oldvar));
   }
   AST_LIST_UNLOCK(oldlist);
   return newlist;
}
static int iax2_exec ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data 
) [static]

Execute IAX2 dialplan switch.

Definition at line 13326 of file chan_iax2.c.

References ast_copy_string(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verb, CACHE_FLAG_EXISTS, find_cache(), iax2_dpcache::flags, LOG_NOTICE, LOG_WARNING, pbx_builtin_getvar_helper(), pbx_exec(), and pbx_findapp().

{
   char odata[256];
   char req[256];
   char *ncontext;
   struct iax2_dpcache *dp = NULL;
   struct ast_app *dial = NULL;
#if 0
   ast_log(LOG_NOTICE, "iax2_exec: con: %s, exten: %s, pri: %d, cid: %s, data: %s, newstack: %d\n", context, exten, priority, callerid ? callerid : "<unknown>", data, newstack);
#endif
   if (priority == 2) {
      /* Indicate status, can be overridden in dialplan */
      const char *dialstatus = pbx_builtin_getvar_helper(chan, "DIALSTATUS");
      if (dialstatus) {
         dial = pbx_findapp(dialstatus);
         if (dial) 
            pbx_exec(chan, dial, "");
      }
      return -1;
   } else if (priority != 1)
      return -1;

   AST_LIST_LOCK(&dpcache);
   if ((dp = find_cache(chan, data, context, exten, priority))) {
      if (dp->flags & CACHE_FLAG_EXISTS) {
         ast_copy_string(odata, data, sizeof(odata));
         ncontext = strchr(odata, '/');
         if (ncontext) {
            *ncontext = '\0';
            ncontext++;
            snprintf(req, sizeof(req), "IAX2/%s/%s@%s", odata, exten, ncontext);
         } else {
            snprintf(req, sizeof(req), "IAX2/%s/%s", odata, exten);
         }
         ast_verb(3, "Executing Dial('%s')\n", req);
      } else {
         AST_LIST_UNLOCK(&dpcache);
         ast_log(LOG_WARNING, "Can't execute nonexistent extension '%s[@%s]' in data '%s'\n", exten, context, data);
         return -1;
      }
   }
   AST_LIST_UNLOCK(&dpcache);

   if ((dial = pbx_findapp("Dial")))
      return pbx_exec(chan, dial, req);
   else
      ast_log(LOG_WARNING, "No dial application registered\n");

   return -1;
}
static int iax2_exists ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data 
) [static]

Part of the IAX2 switch interface.

Definition at line 13257 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), CACHE_FLAG_EXISTS, find_cache(), iax2_dpcache::flags, LOG_NOTICE, and LOG_WARNING.

{
   int res = 0;
   struct iax2_dpcache *dp = NULL;
#if 0
   ast_log(LOG_NOTICE, "iax2_exists: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
#endif
   if ((priority != 1) && (priority != 2))
      return 0;

   AST_LIST_LOCK(&dpcache);
   if ((dp = find_cache(chan, data, context, exten, priority))) {
      if (dp->flags & CACHE_FLAG_EXISTS)
         res = 1;
   } else {
      ast_log(LOG_WARNING, "Unable to make DP cache\n");
   }
   AST_LIST_UNLOCK(&dpcache);

   return res;
}
static int iax2_fixup ( struct ast_channel oldchannel,
struct ast_channel newchan 
) [static]

Definition at line 4132 of file chan_iax2.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), LOG_WARNING, chan_iax2_pvt::owner, PTR_TO_CALLNO, and ast_channel::tech_pvt.

{
   unsigned short callno = PTR_TO_CALLNO(newchan->tech_pvt);
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno])
      iaxs[callno]->owner = newchan;
   else
      ast_log(LOG_WARNING, "Uh, this isn't a good sign...\n");
   ast_mutex_unlock(&iaxsl[callno]);
   return 0;
}
static void iax2_free_variable_datastore ( void *  old) [static]

Definition at line 1265 of file chan_iax2.c.

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and ast_var_t::entries.

{
   AST_LIST_HEAD(, ast_var_t) *oldlist = old;
   struct ast_var_t *oldvar;

   AST_LIST_LOCK(oldlist);
   while ((oldvar = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
      ast_free(oldvar);
   }
   AST_LIST_UNLOCK(oldlist);
   AST_LIST_HEAD_DESTROY(oldlist);
   ast_free(oldlist);
}
static int iax2_getpeername ( struct sockaddr_in  sin,
char *  host,
int  len 
) [static]

Definition at line 1627 of file chan_iax2.c.

References iax2_peer::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_copy_string(), iax2_peer::name, peer_unref(), and realtime_peer().

Referenced by __find_callno().

{
   struct iax2_peer *peer = NULL;
   int res = 0;
   struct ao2_iterator i;

   i = ao2_iterator_init(peers, 0);
   while ((peer = ao2_iterator_next(&i))) {
      if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
          (peer->addr.sin_port == sin.sin_port)) {
         ast_copy_string(host, peer->name, len);
         peer_unref(peer);
         res = 1;
         break;
      }
      peer_unref(peer);
   }
   ao2_iterator_destroy(&i);

   if (!peer) {
      peer = realtime_peer(NULL, &sin);
      if (peer) {
         ast_copy_string(host, peer->name, len);
         peer_unref(peer);
         res = 1;
      }
   }

   return res;
}
static int iax2_getpeertrunk ( struct sockaddr_in  sin) [static]

Definition at line 5426 of file chan_iax2.c.

References iax2_peer::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_test_flag, IAX_TRUNK, and peer_unref().

Referenced by check_access().

{
   struct iax2_peer *peer;
   int res = 0;
   struct ao2_iterator i;

   i = ao2_iterator_init(peers, 0);
   while ((peer = ao2_iterator_next(&i))) {
      if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
          (peer->addr.sin_port == sin.sin_port)) {
         res = ast_test_flag(peer, IAX_TRUNK);
         peer_unref(peer);
         break;
      }
      peer_unref(peer);
   }
   ao2_iterator_destroy(&i);

   return res;
}
static int iax2_hangup ( struct ast_channel c) [static]

Definition at line 5003 of file chan_iax2.c.

References ast_debug, AST_FRAME_IAX, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_thread_add(), ast_test_flag, ast_verb, iax_ie_data::buf, CALLNO_TO_PTR, ast_channel::hangupcause, iax2_destroy(), iax2_predestroy(), IAX_ALREADYGONE, IAX_COMMAND_HANGUP, iax_ie_append_byte(), IAX_IE_CAUSECODE, LOG_ERROR, LOG_WARNING, ast_channel::name, iax_ie_data::pos, PTR_TO_CALLNO, scheduled_destroy(), send_command_final(), and ast_channel::tech_pvt.

{
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   struct iax_ie_data ied;
   int alreadygone;
   memset(&ied, 0, sizeof(ied));
   ast_mutex_lock(&iaxsl[callno]);
   if (callno && iaxs[callno]) {
      ast_debug(1, "We're hanging up %s now...\n", c->name);
      alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
      /* Send the hangup unless we have had a transmission error or are already gone */
      iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
      if (!iaxs[callno]->error && !alreadygone) {
         if (send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1)) {
            ast_log(LOG_WARNING, "No final packet could be sent for callno %d\n", callno);
         }
         if (!iaxs[callno]) {
            ast_mutex_unlock(&iaxsl[callno]);
            return 0;
         }
      }
      /* Explicitly predestroy it */
      iax2_predestroy(callno);
      /* If we were already gone to begin with, destroy us now */
      if (iaxs[callno] && alreadygone) {
         ast_debug(1, "Really destroying %s now...\n", c->name);
         iax2_destroy(callno);
      } else if (iaxs[callno]) {
         if (ast_sched_thread_add(sched, 10000, scheduled_destroy, CALLNO_TO_PTR(callno)) < 0) {
            ast_log(LOG_ERROR, "Unable to schedule iax2 callno %d destruction?!!  Destroying immediately.\n", callno);
            iax2_destroy(callno);
         }
      }
   } else if (c->tech_pvt) {
      /* If this call no longer exists, but the channel still
       * references it we need to set the channel's tech_pvt to null
       * to avoid ast_channel_free() trying to free it.
       */
      c->tech_pvt = NULL;
   }
   ast_mutex_unlock(&iaxsl[callno]);
   ast_verb(3, "Hungup '%s'\n", c->name);
   return 0;
}
static int iax2_indicate ( struct ast_channel c,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 5369 of file chan_iax2.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), chan_iax2_pvt::callno, chan_iax2_pvt::mohinterpret, PTR_TO_CALLNO, send_command(), ast_channel::tech_pvt, and wait_for_peercallno().

{
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   struct chan_iax2_pvt *pvt;
   int res = 0;

   if (iaxdebug)
      ast_debug(1, "Indicating condition %d\n", condition);

   ast_mutex_lock(&iaxsl[callno]);
   pvt = iaxs[callno];

   if (wait_for_peercallno(pvt)) {
      res = -1;
      goto done;
   }

   switch (condition) {
   case AST_CONTROL_HOLD:
      if (strcasecmp(pvt->mohinterpret, "passthrough")) {
         ast_moh_start(c, data, pvt->mohinterpret);
         goto done;
      }
      break;
   case AST_CONTROL_UNHOLD:
      if (strcasecmp(pvt->mohinterpret, "passthrough")) {
         ast_moh_stop(c);
         goto done;
      }
   }

   res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);

done:
   ast_mutex_unlock(&iaxsl[callno]);

   return res;
}
static int iax2_key_rotate ( const void *  vpvt) [static]

Definition at line 5121 of file chan_iax2.c.

References AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_sched_thread_add(), iax_ie_data::buf, build_ecx_key(), chan_iax2_pvt::callno, IAX_COMMAND_RTKEY, IAX_DEBUGDIGEST, iax_ie_append_raw(), IAX_IE_CHALLENGE, chan_iax2_pvt::keyrotateid, MD5Final(), MD5Init(), MD5Update(), iax_ie_data::pos, and send_command().

Referenced by iax2_send().

{
   int res = 0;
   struct chan_iax2_pvt *pvt = (void *) vpvt;
   struct MD5Context md5;
   char key[17] = "";
   struct iax_ie_data ied = {
      .pos = 0,   
   };
   
   ast_mutex_lock(&iaxsl[pvt->callno]);
   pvt->keyrotateid = 
      ast_sched_thread_add(sched, 120000 + (ast_random() % 180001), iax2_key_rotate, vpvt);

   snprintf(key, sizeof(key), "%lX", ast_random());

   MD5Init(&md5);
   MD5Update(&md5, (unsigned char *) key, strlen(key));
   MD5Final((unsigned char *) key, &md5);

   IAX_DEBUGDIGEST("Sending", key);

   iax_ie_append_raw(&ied, IAX_IE_CHALLENGE, key, 16);

   res = send_command(pvt, AST_FRAME_IAX, IAX_COMMAND_RTKEY, 0, ied.buf, ied.pos, -1);

   build_ecx_key((unsigned char *) key, pvt);

   ast_mutex_unlock(&iaxsl[pvt->callno]);

   return res;
}
static void iax2_lock_owner ( int  callno) [static]

Definition at line 1201 of file chan_iax2.c.

References ast_channel_trylock, and DEADLOCK_AVOIDANCE.

Referenced by iax2_queue_control_data(), iax2_queue_frame(), iax2_queue_hangup(), schedule_delivery(), and socket_process().

{
   for (;;) {
      if (!iaxs[callno] || !iaxs[callno]->owner) {
         /* There is no owner lock to get. */
         break;
      }
      if (!ast_channel_trylock(iaxs[callno]->owner)) {
         /* We got the lock */
         break;
      }
      /* Avoid deadlock by pausing and trying again */
      DEADLOCK_AVOIDANCE(&iaxsl[callno]);
   }
}
static int iax2_matchmore ( struct ast_channel chan,
const char *  context,
const char *  exten,
int  priority,
const char *  callerid,
const char *  data 
) [static]

Part of the IAX2 Switch interface.

Definition at line 13303 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), CACHE_FLAG_MATCHMORE, find_cache(), iax2_dpcache::flags, LOG_NOTICE, and LOG_WARNING.

{
   int res = 0;
   struct iax2_dpcache *dp = NULL;
#if 0
   ast_log(LOG_NOTICE, "iax2_matchmore: con: %s, exten: %s, pri: %d, cid: %s, data: %s\n", context, exten, priority, callerid ? callerid : "<unknown>", data);
#endif
   if ((priority != 1) && (priority != 2))
      return 0;

   AST_LIST_LOCK(&dpcache);
   if ((dp = find_cache(chan, data, context, exten, priority))) {
      if (dp->flags & CACHE_FLAG_MATCHMORE)
         res = 1;
   } else {
      ast_log(LOG_WARNING, "Unable to make DP cache\n");
   }
   AST_LIST_UNLOCK(&dpcache);

   return res;
}
static int iax2_poke_noanswer ( const void *  data) [static]

Definition at line 11510 of file chan_iax2.c.

References __iax2_poke_noanswer(), peer_unref(), iax2_peer::pokeexpire, and schedule_action.

Referenced by iax2_poke_peer().

{
   struct iax2_peer *peer = (struct iax2_peer *)data;
   peer->pokeexpire = -1;
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__iax2_poke_noanswer, data))
#endif      
      __iax2_poke_noanswer(data);
   peer_unref(peer);
   return 0;
}
static int iax2_poke_peer ( struct iax2_peer peer,
int  heldcall 
) [static]

Definition at line 11531 of file chan_iax2.c.

References add_empty_calltoken_ie(), iax2_peer::addr, AST_FRAME_IAX, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_thread_del, iax_ie_data::buf, iax2_peer::callno, DEFAULT_MAXMS, iax2_peer::dnsmgr, find_callno(), iax2_peer::historicms, iax2_destroy(), iax2_poke_noanswer(), iax2_sched_add(), IAX_COMMAND_POKE, iax2_peer::lastms, LOG_NOTICE, LOG_WARNING, iax2_peer::maxms, iax2_peer::name, NEW_FORCE, peer_ref(), peer_unref(), chan_iax2_pvt::peerpoke, chan_iax2_pvt::pingtime, iax2_peer::pokeexpire, iax2_peer::pokefreqnotok, iax_ie_data::pos, send_command(), and iax2_peer::sockfd.

Referenced by __iax2_poke_peer_s(), iax2_poke_peer_cb(), poke_all_peers(), reg_source_db(), and update_registry().

{
   int callno;
   if (!peer->maxms || (!peer->addr.sin_addr.s_addr && !peer->dnsmgr)) {
      /* IF we have no IP without dnsmgr, or this isn't to be monitored, return
        immediately after clearing things out */
      peer->lastms = 0;
      peer->historicms = 0;
      peer->pokeexpire = -1;
      peer->callno = 0;
      return 0;
   }

   /* The peer could change the callno inside iax2_destroy, since we do deadlock avoidance */
   if ((callno = peer->callno) > 0) {
      ast_log(LOG_NOTICE, "Still have a callno...\n");
      ast_mutex_lock(&iaxsl[callno]);
      iax2_destroy(callno);
      ast_mutex_unlock(&iaxsl[callno]);
   }
   if (heldcall)
      ast_mutex_unlock(&iaxsl[heldcall]);
   callno = peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
   if (heldcall)
      ast_mutex_lock(&iaxsl[heldcall]);
   if (peer->callno < 1) {
      ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
      return -1;
   }

   /* Speed up retransmission times for this qualify call */
   iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
   iaxs[peer->callno]->peerpoke = peer;

   if (peer->pokeexpire > -1) {
      if (!ast_sched_thread_del(sched, peer->pokeexpire)) {
         peer->pokeexpire = -1;
         peer_unref(peer);
      }
   }
 
   /* Queue up a new task to handle no reply */
   /* If the host is already unreachable then use the unreachable interval instead */
   if (peer->lastms < 0)
      peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer_ref(peer));
   else
      peer->pokeexpire = iax2_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer_ref(peer));

   if (peer->pokeexpire == -1)
      peer_unref(peer);

   /* And send the poke */
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      struct iax_ie_data ied = {
         .buf = { 0 },
         .pos = 0,
      };
      add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
      send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, ied.buf, ied.pos, -1);
   }
   ast_mutex_unlock(&iaxsl[callno]);

   return 0;
}
static int iax2_poke_peer_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 11522 of file chan_iax2.c.

References iax2_poke_peer().

Referenced by load_module().

{
   struct iax2_peer *peer = obj;

   iax2_poke_peer(peer, 0);

   return 0;
}
static int iax2_poke_peer_s ( const void *  data) [static]

Definition at line 8759 of file chan_iax2.c.

References __iax2_poke_peer_s(), iax2_peer::pokeexpire, and schedule_action.

Referenced by __iax2_poke_noanswer(), and socket_process().

{
   struct iax2_peer *peer = (struct iax2_peer *)data;
   peer->pokeexpire = -1;
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__iax2_poke_peer_s, data))
#endif      
      __iax2_poke_peer_s(data);
   return 0;
}
static int iax2_predestroy ( int  callno) [static]
Note:
Since this function calls iax2_queue_hangup(), the pvt struct for the given call number may disappear during its execution.

Definition at line 3213 of file chan_iax2.c.

References ast_module_unref(), ast_set_flag, ast_test_flag, chan_iax2_pvt::callno, iax2_destroy_helper(), iax2_queue_hangup(), IAX_ALREADYGONE, chan_iax2_pvt::owner, ast_module_info::self, and ast_channel::tech_pvt.

Referenced by iax2_hangup(), and send_command_final().

{
   struct ast_channel *c = NULL;
   struct chan_iax2_pvt *pvt = iaxs[callno];

   if (!pvt)
      return -1;

   if (!ast_test_flag(pvt, IAX_ALREADYGONE)) {
      iax2_destroy_helper(pvt);
      ast_set_flag(pvt, IAX_ALREADYGONE); 
   }

   if ((c = pvt->owner)) {
      c->tech_pvt = NULL;
      iax2_queue_hangup(callno);
      pvt->owner = NULL;
      ast_module_unref(ast_module_info->self);
   }

   return 0;
}
static void * iax2_process_thread ( void *  data) [static]

Note:
For some reason, idle threads are exiting without being removed from an idle list, which is causing memory corruption. Forcibly remove it from the list, if it's there.

Definition at line 11172 of file chan_iax2.c.

References iax2_thread::actions, ast_atomic_fetchadd_int(), ast_cond_timedwait(), ast_cond_wait(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_tvadd(), ast_tvnow(), iax2_thread::checktime, iax2_thread::cond, iax2_thread::curfunc, handle_deferred_full_frames(), iax2_process_thread_cleanup(), IAX_IOSTATE_IDLE, IAX_IOSTATE_PROCESSING, IAX_IOSTATE_READY, IAX_IOSTATE_SCHEDREADY, IAX_THREAD_TYPE_DYNAMIC, iaxactivethreadcount, iaxdynamicthreadcount, iax2_thread::init_cond, iax2_thread::init_lock, insert_idle_thread(), iax2_thread::iostate, iax2_thread::lock, iax2_thread::scheddata, iax2_thread::schedfunc, signal_condition(), socket_process(), iax2_thread::stop, thread, and iax2_thread::type.

Referenced by find_idle_thread(), and start_network_thread().

{
   struct iax2_thread *thread = data;
   struct timeval wait;
   struct timespec ts;
   int put_into_idle = 0;
   int first_time = 1;
   int old_state;

   ast_atomic_fetchadd_int(&iaxactivethreadcount, 1);

   pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
   pthread_cleanup_push(iax2_process_thread_cleanup, data);

   for (;;) {
      /* Wait for something to signal us to be awake */
      ast_mutex_lock(&thread->lock);

      if (thread->stop) {
         ast_mutex_unlock(&thread->lock);
         break;
      }

      /* Flag that we're ready to accept signals */
      if (first_time) {
         signal_condition(&thread->init_lock, &thread->init_cond);
         first_time = 0;
      }

      /* Put into idle list if applicable */
      if (put_into_idle) {
         insert_idle_thread(thread);
      }

      if (thread->type == IAX_THREAD_TYPE_DYNAMIC) {
         struct iax2_thread *t = NULL;
         /* Wait to be signalled or time out */
         wait = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
         ts.tv_sec = wait.tv_sec;
         ts.tv_nsec = wait.tv_usec * 1000;
         if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
            /* This thread was never put back into the available dynamic
             * thread list, so just go away. */
            if (!put_into_idle || thread->stop) {
               ast_mutex_unlock(&thread->lock);
               break;
            }
            AST_LIST_LOCK(&dynamic_list);
            /* Account for the case where this thread is acquired *right* after a timeout */
            if ((t = AST_LIST_REMOVE(&dynamic_list, thread, list)))
               ast_atomic_fetchadd_int(&iaxdynamicthreadcount, -1);
            AST_LIST_UNLOCK(&dynamic_list);
            if (t) {
               /* This dynamic thread timed out waiting for a task and was
                * not acquired immediately after the timeout, 
                * so it's time to go away. */
               ast_mutex_unlock(&thread->lock);
               break;
            }
            /* Someone grabbed our thread *right* after we timed out.
             * Wait for them to set us up with something to do and signal
             * us to continue. */
            wait = ast_tvadd(ast_tvnow(), ast_samp2tv(30000, 1000));
            ts.tv_sec = wait.tv_sec;
            ts.tv_nsec = wait.tv_usec * 1000;
            if (ast_cond_timedwait(&thread->cond, &thread->lock, &ts) == ETIMEDOUT) {
               ast_mutex_unlock(&thread->lock);
               break;
            }
         }
      } else {
         ast_cond_wait(&thread->cond, &thread->lock);
      }

      /* Go back into our respective list */
      put_into_idle = 1;

      ast_mutex_unlock(&thread->lock);

      if (thread->stop) {
         break;
      }

      if (thread->iostate == IAX_IOSTATE_IDLE)
         continue;

      /* See what we need to do */
      switch (thread->iostate) {
      case IAX_IOSTATE_READY:
         thread->actions++;
         thread->iostate = IAX_IOSTATE_PROCESSING;
         socket_process(thread);
         handle_deferred_full_frames(thread);
         break;
      case IAX_IOSTATE_SCHEDREADY:
         thread->actions++;
         thread->iostate = IAX_IOSTATE_PROCESSING;
#ifdef SCHED_MULTITHREADED
         thread->schedfunc(thread->scheddata);
#endif      
      default:
         break;
      }
      time(&thread->checktime);
      thread->iostate = IAX_IOSTATE_IDLE;
#ifdef DEBUG_SCHED_MULTITHREAD
      thread->curfunc[0]='\0';
#endif      

      /* The network thread added us to the active_thread list when we were given
       * frames to process, Now that we are done, we must remove ourselves from
       * the active list, and return to the idle list */
      AST_LIST_LOCK(&active_list);
      AST_LIST_REMOVE(&active_list, thread, list);
      AST_LIST_UNLOCK(&active_list);

      /* Make sure another frame didn't sneak in there after we thought we were done. */
      handle_deferred_full_frames(thread);
   }

   /*!\note For some reason, idle threads are exiting without being removed
    * from an idle list, which is causing memory corruption.  Forcibly remove
    * it from the list, if it's there.
    */
   AST_LIST_LOCK(&idle_list);
   AST_LIST_REMOVE(&idle_list, thread, list);
   AST_LIST_UNLOCK(&idle_list);

   AST_LIST_LOCK(&dynamic_list);
   AST_LIST_REMOVE(&dynamic_list, thread, list);
   AST_LIST_UNLOCK(&dynamic_list);

   /* I am exiting here on my own volition, I need to clean up my own data structures
   * Assume that I am no longer in any of the lists (idle, active, or dynamic)
   */
   pthread_cleanup_pop(1);
   return NULL;
}
static int iax2_provision ( struct sockaddr_in *  end,
int  sockfd,
char *  dest,
const char *  template,
int  force 
) [static]

Definition at line 11367 of file chan_iax2.c.

References ast_debug, AST_FRAME_IAX, ast_mutex_unlock(), ast_set_flag, auto_hangup(), chan_iax2_pvt::autoid, iax_ie_data::buf, create_addr(), find_callno_locked(), iax2_sched_replace(), IAX_COMMAND_PROVISION, iax_ie_append_raw(), IAX_IE_PROVISIONING, IAX_PROVISION, iax_provision_build(), NEW_FORCE, iax_ie_data::pos, send_command(), iax2_trunk_peer::sockfd, and create_addr_info::sockfd.

Referenced by check_provisioning(), handle_cli_iax2_provision(), and iax2_prov_app().

{
   /* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
      is found for template */
   struct iax_ie_data provdata;
   struct iax_ie_data ied;
   unsigned int sig;
   struct sockaddr_in sin;
   int callno;
   struct create_addr_info cai;

   memset(&cai, 0, sizeof(cai));

   ast_debug(1, "Provisioning '%s' from template '%s'\n", dest, template);

   if (iax_provision_build(&provdata, &sig, template, force)) {
      ast_debug(1, "No provisioning found for template '%s'\n", template);
      return 0;
   }

   if (end) {
      memcpy(&sin, end, sizeof(sin));
      cai.sockfd = sockfd;
   } else if (create_addr(dest, NULL, &sin, &cai))
      return -1;

   /* Build the rest of the message */
   memset(&ied, 0, sizeof(ied));
   iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);

   callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
   if (!callno)
      return -1;

   if (iaxs[callno]) {
      /* Schedule autodestruct in case they don't ever give us anything back */
      iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
         sched, 15000, auto_hangup, (void *)(long)callno);
      ast_set_flag(iaxs[callno], IAX_PROVISION);
      /* Got a call number now, so go ahead and send the provisioning information */
      send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PROVISION, 0, ied.buf, ied.pos, -1);
   }
   ast_mutex_unlock(&iaxsl[callno]);

   return 1;
}
static int iax2_queue_control_data ( int  callno,
enum ast_control_frame_type  control,
const void *  data,
size_t  datalen 
) [static]

Queue a control frame on the ast_channel owner.

This function queues a control frame on the owner of the IAX2 pvt struct that is active for the given call number.

Precondition:
Assumes lock for callno is already held.
Note:
IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] was valid before calling it, it may no longer be valid after calling it. This function may unlock and lock the mutex associated with this callno, meaning that another thread may grab it and destroy the call.

Definition at line 2846 of file chan_iax2.c.

References ast_channel_unlock, ast_queue_control_data(), and iax2_lock_owner().

Referenced by socket_process().

{
   iax2_lock_owner(callno);
   if (iaxs[callno] && iaxs[callno]->owner) {
      ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
      ast_channel_unlock(iaxs[callno]->owner);
   }
   return 0;
}
static int iax2_queue_frame ( int  callno,
struct ast_frame f 
) [static]

Queue a frame to a call's owning asterisk channel.

Precondition:
This function assumes that iaxsl[callno] is locked when called.
Note:
IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] was valid before calling it, it may no longer be valid after calling it. This function may unlock and lock the mutex associated with this callno, meaning that another thread may grab it and destroy the call.

Definition at line 2800 of file chan_iax2.c.

References ast_channel_unlock, ast_queue_frame(), and iax2_lock_owner().

Referenced by __attempt_transmit(), __auto_congest(), __do_deliver(), __get_from_jb(), and socket_process().

{
   iax2_lock_owner(callno);
   if (iaxs[callno] && iaxs[callno]->owner) {
      ast_queue_frame(iaxs[callno]->owner, f);
      ast_channel_unlock(iaxs[callno]->owner);
   }
   return 0;
}
static int iax2_queue_hangup ( int  callno) [static]

Queue a hangup frame on the ast_channel owner.

This function queues a hangup frame on the owner of the IAX2 pvt struct that is active for the given call number.

Precondition:
Assumes lock for callno is already held.
Note:
IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] was valid before calling it, it may no longer be valid after calling it. This function may unlock and lock the mutex associated with this callno, meaning that another thread may grab it and destroy the call.

Definition at line 2823 of file chan_iax2.c.

References ast_channel_unlock, ast_queue_hangup(), and iax2_lock_owner().

Referenced by iax2_predestroy().

{
   iax2_lock_owner(callno);
   if (iaxs[callno] && iaxs[callno]->owner) {
      ast_queue_hangup(iaxs[callno]->owner);
      ast_channel_unlock(iaxs[callno]->owner);
   }
   return 0;
}
static struct ast_frame * iax2_read ( struct ast_channel c) [static, read]

Definition at line 5115 of file chan_iax2.c.

References ast_log(), ast_null_frame, and LOG_NOTICE.

{
   ast_log(LOG_NOTICE, "I should never be called!\n");
   return &ast_null_frame;
}
static int iax2_register ( const char *  value,
int  lineno 
) [static]

Definition at line 8214 of file chan_iax2.c.

References ast_copy_string(), ast_log(), copy(), hostname, iax2_append_register(), LOG_WARNING, secret, strsep(), and iax2_registry::username.

Referenced by set_config().

{
   char copy[256];
   char *username, *hostname, *secret;
   char *porta;
   char *stringp=NULL;
   
   if (!value)
      return -1;

   ast_copy_string(copy, value, sizeof(copy));
   stringp = copy;
   username = strsep(&stringp, "@");
   hostname = strsep(&stringp, "@");

   if (!hostname) {
      ast_log(LOG_WARNING, "Format for registration is user[:secret]@host[:port] at line %d\n", lineno);
      return -1;
   }

   stringp = username;
   username = strsep(&stringp, ":");
   secret = strsep(&stringp, ":");
   stringp = hostname;
   hostname = strsep(&stringp, ":");
   porta = strsep(&stringp, ":");
   
   if (porta && !atoi(porta)) {
      ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
      return -1;
   }

   return iax2_append_register(hostname, username, secret, porta);
}
static struct ast_channel * iax2_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 11607 of file chan_iax2.c.

References ast_best_codec(), AST_CAUSE_CONGESTION, AST_CAUSE_UNREGISTERED, ast_copy_flags, ast_getformatname(), ast_hangup(), ast_iax2_new(), ast_log(), ast_mutex_unlock(), AST_STATE_DOWN, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_translator_best_choice(), create_addr_info::capability, create_addr(), find_callno_locked(), format, create_addr_info::found, iax2_capability, IAX_FORCEJITTERBUF, IAX_NOTRANSFER, IAX_SENDANI, IAX_TRANSFERMEDIA, IAX_TRUNK, IAX_USEJITTERBUF, LOG_WARNING, make_trunk(), create_addr_info::maxtime, chan_iax2_pvt::maxtime, ast_channel::name, ast_channel::nativeformats, NEW_FORCE, parse_dial_string(), parsed_dial_string::peer, parsed_dial_string::port, ast_channel::readformat, create_addr_info::sockfd, and ast_channel::writeformat.

{
   int callno;
   int res;
   int fmt, native;
   struct sockaddr_in sin;
   struct ast_channel *c;
   struct parsed_dial_string pds;
   struct create_addr_info cai;
   char *tmpstr;

   memset(&pds, 0, sizeof(pds));
   tmpstr = ast_strdupa(data);
   parse_dial_string(tmpstr, &pds);

   if (ast_strlen_zero(pds.peer)) {
      ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", (char *) data);
      return NULL;
   }
          
   memset(&cai, 0, sizeof(cai));
   cai.capability = iax2_capability;

   ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
   
   /* Populate our address from the given */
   if (create_addr(pds.peer, NULL, &sin, &cai)) {
      *cause = AST_CAUSE_UNREGISTERED;
      return NULL;
   }

   if (pds.port)
      sin.sin_port = htons(atoi(pds.port));

   callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
   if (callno < 1) {
      ast_log(LOG_WARNING, "Unable to create call\n");
      *cause = AST_CAUSE_CONGESTION;
      return NULL;
   }

   /* If this is a trunk, update it now */
   ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
   if (ast_test_flag(&cai, IAX_TRUNK)) {
      int new_callno;
      if ((new_callno = make_trunk(callno, 1)) != -1)
         callno = new_callno;
   }
   iaxs[callno]->maxtime = cai.maxtime;
   if (cai.found)
      ast_string_field_set(iaxs[callno], host, pds.peer);

   c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability);

   ast_mutex_unlock(&iaxsl[callno]);

   if (c) {
      /* Choose a format we can live with */
      if (c->nativeformats & format) 
         c->nativeformats &= format;
      else {
         native = c->nativeformats;
         fmt = format;
         res = ast_translator_best_choice(&fmt, &native);
         if (res < 0) {
            ast_log(LOG_WARNING, "Unable to create translator path for %s to %s on %s\n",
               ast_getformatname(c->nativeformats), ast_getformatname(fmt), c->name);
            ast_hangup(c);
            return NULL;
         }
         c->nativeformats = native;
      }
      c->readformat = ast_best_codec(c->nativeformats);
      c->writeformat = c->readformat;
   }

   return c;
}
static int iax2_sched_add ( struct ast_sched_thread st,
int  when,
ast_sched_cb  callback,
const void *  data 
) [static]
static int iax2_sched_replace ( int  id,
struct ast_sched_thread st,
int  when,
ast_sched_cb  callback,
const void *  data 
) [static]

Definition at line 1393 of file chan_iax2.c.

References ast_sched_thread_add(), and ast_sched_thread_del.

Referenced by auth_fail(), iax2_ack_registry(), iax2_do_register(), iax2_dprequest(), iax2_provision(), and update_jbsched().

{
   ast_sched_thread_del(st, id);

   return ast_sched_thread_add(st, when, callback, data);
}
static int iax2_send ( struct chan_iax2_pvt pvt,
struct ast_frame f,
unsigned int  ts,
int  seqno,
int  now,
int  transfer,
int  final 
) [static]

Definition at line 6078 of file chan_iax2.c.

References chan_iax2_pvt::addr, iax_frame::af, chan_iax2_pvt::aseqno, AST_FRAME_IAX, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_test_flag, calc_timestamp(), ast_iax2_mini_hdr::callno, ast_iax2_video_hdr::callno, chan_iax2_pvt::callno, iax_frame::callno, compress_subclass(), ast_iax2_full_hdr::csub, iax_frame::data, ast_frame::data, iax_frame::datalen, ast_frame::datalen, ast_iax2_full_hdr::dcallno, iax_frame::dcallno, DIRECTION_OUTGRESS, iax_frame::ecx, chan_iax2_pvt::ecx, chan_iax2_pvt::encmethods, iax_frame::encmethods, encrypt_frame(), iax_frame::final, chan_iax2_pvt::first_iax_message, ast_frame::frametype, iax2_key_rotate(), iax2_transmit(), iax2_trunk_queue(), IAX_CALLENCRYPTED, IAX_COMMAND_ACK, IAX_ENCRYPTED, IAX_FLAG_FULL, iax_frame_new(), iax_frame_wrap(), IAX_KEYPOPULATED, iax_outputframe(), IAX_TRUNK, ast_iax2_full_hdr::iseqno, chan_iax2_pvt::iseqno, iax_frame::iseqno, chan_iax2_pvt::keyrotateid, chan_iax2_pvt::last_iax_message, chan_iax2_pvt::lastsent, iax2_trunk_peer::lastsent, chan_iax2_pvt::lastvsent, LOG_NOTICE, LOG_WARNING, MARK_IAX_SUBCLASS_TX, MAX_RETRY_TIME, MIN_RETRY_TIME, chan_iax2_pvt::mydcx, iax_frame::mydcx, ast_iax2_full_hdr::oseqno, chan_iax2_pvt::oseqno, iax_frame::oseqno, chan_iax2_pvt::peercallno, chan_iax2_pvt::pingtime, ast_frame::ptr, iax_frame::retries, iax_frame::retrytime, ast_iax2_full_hdr::scallno, iax_frame::semirand, chan_iax2_pvt::semirand, send_packet(), ast_frame::subclass, chan_iax2_pvt::svideoformat, chan_iax2_pvt::svoiceformat, chan_iax2_pvt::transfer, transfer, iax_frame::transfer, TRANSFER_MEDIAPASS, chan_iax2_pvt::transfercallno, chan_iax2_pvt::transferring, ast_iax2_mini_hdr::ts, ast_iax2_video_hdr::ts, ast_iax2_full_hdr::ts, iax_frame::ts, ast_iax2_full_hdr::type, and ast_iax2_video_hdr::zeros.

Referenced by __send_command(), iax2_write(), send_signaling(), and socket_process().

{
   /* Queue a packet for delivery on a given private structure.  Use "ts" for
      timestamp, or calculate if ts is 0.  Send immediately without retransmission
      or delayed, with retransmission */
   struct ast_iax2_full_hdr *fh;
   struct ast_iax2_mini_hdr *mh;
   struct ast_iax2_video_hdr *vh;
   struct {
      struct iax_frame fr2;
      unsigned char buffer[4096];
   } frb;
   struct iax_frame *fr;
   int res;
   int sendmini=0;
   unsigned int lastsent;
   unsigned int fts;

   frb.fr2.afdatalen = sizeof(frb.buffer);

   if (!pvt) {
      ast_log(LOG_WARNING, "No private structure for packet?\n");
      return -1;
   }
   
   lastsent = pvt->lastsent;

   /* Calculate actual timestamp */
   fts = calc_timestamp(pvt, ts, f);

   /* Bail here if this is an "interp" frame; we don't want or need to send these placeholders out
    * (the endpoint should detect the lost packet itself).  But, we want to do this here, so that we
    * increment the "predicted timestamps" for voice, if we're predicting */
   if(f->frametype == AST_FRAME_VOICE && f->datalen == 0)
      return 0;
#if 0
   ast_log(LOG_NOTICE, 
      "f->frametype %c= AST_FRAME_VOICE, %sencrypted, %srotation scheduled...\n",
      *("=!" + (f->frametype == AST_FRAME_VOICE)),
      IAX_CALLENCRYPTED(pvt) ? "" : "not ",
      pvt->keyrotateid != -1 ? "" : "no "
   );
#endif
   if (pvt->keyrotateid == -1 && f->frametype == AST_FRAME_VOICE && IAX_CALLENCRYPTED(pvt)) {
      iax2_key_rotate(pvt);
   }

   if ((ast_test_flag(pvt, IAX_TRUNK) || 
         (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) ||
         ((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L))))
      /* High two bytes are the same on timestamp, or sending on a trunk */ &&
       (f->frametype == AST_FRAME_VOICE) 
      /* is a voice frame */ &&
      (f->subclass == pvt->svoiceformat) 
      /* is the same type */ ) {
         /* Force immediate rather than delayed transmission */
         now = 1;
         /* Mark that mini-style frame is appropriate */
         sendmini = 1;
   }
   if ( f->frametype == AST_FRAME_VIDEO ) {
      /*
       * If the lower 15 bits of the timestamp roll over, or if
       * the video format changed then send a full frame.
       * Otherwise send a mini video frame
       */
      if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) &&
          ((f->subclass & ~0x1) == pvt->svideoformat)
         ) {
         now = 1;
         sendmini = 1;
      } else {
         now = 0;
         sendmini = 0;
      }
      pvt->lastvsent = fts;
   }
   if (f->frametype == AST_FRAME_IAX) {
      /* 0x8000 marks this message as TX:, this bit will be stripped later */
      pvt->last_iax_message = f->subclass | MARK_IAX_SUBCLASS_TX;
      if (!pvt->first_iax_message) {
         pvt->first_iax_message = pvt->last_iax_message;
      }
   }
   /* Allocate an iax_frame */
   if (now) {
      fr = &frb.fr2;
   } else
      fr = iax_frame_new(DIRECTION_OUTGRESS, ast_test_flag(pvt, IAX_ENCRYPTED) ? f->datalen + 32 : f->datalen, (f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO));
   if (!fr) {
      ast_log(LOG_WARNING, "Out of memory\n");
      return -1;
   }
   /* Copy our prospective frame into our immediate or retransmitted wrapper */
   iax_frame_wrap(fr, f);

   fr->ts = fts;
   fr->callno = pvt->callno;
   fr->transfer = transfer;
   fr->final = final;
   fr->encmethods = 0;
   if (!sendmini) {
      /* We need a full frame */
      if (seqno > -1)
         fr->oseqno = seqno;
      else
         fr->oseqno = pvt->oseqno++;
      fr->iseqno = pvt->iseqno;
      fh = (struct ast_iax2_full_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_full_hdr));
      fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
      fh->ts = htonl(fr->ts);
      fh->oseqno = fr->oseqno;
      if (transfer) {
         fh->iseqno = 0;
      } else
         fh->iseqno = fr->iseqno;
      /* Keep track of the last thing we've acknowledged */
      if (!transfer)
         pvt->aseqno = fr->iseqno;
      fh->type = fr->af.frametype & 0xFF;
      if (fr->af.frametype == AST_FRAME_VIDEO)
         fh->csub = compress_subclass(fr->af.subclass & ~0x1) | ((fr->af.subclass & 0x1) << 6);
      else
         fh->csub = compress_subclass(fr->af.subclass);
      if (transfer) {
         fr->dcallno = pvt->transfercallno;
      } else
         fr->dcallno = pvt->peercallno;
      fh->dcallno = htons(fr->dcallno);
      fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
      fr->data = fh;
      fr->retries = 0;
      /* Retry after 2x the ping time has passed */
      fr->retrytime = pvt->pingtime * 2;
      if (fr->retrytime < MIN_RETRY_TIME)
         fr->retrytime = MIN_RETRY_TIME;
      if (fr->retrytime > MAX_RETRY_TIME)
         fr->retrytime = MAX_RETRY_TIME;
      /* Acks' don't get retried */
      if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
         fr->retries = -1;
      else if (f->frametype == AST_FRAME_VOICE)
         pvt->svoiceformat = f->subclass;
      else if (f->frametype == AST_FRAME_VIDEO)
         pvt->svideoformat = f->subclass & ~0x1;
      if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
         if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
            if (fr->transfer)
               iax_outputframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
            else
               iax_outputframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
            encrypt_frame(&pvt->ecx, fh, pvt->semirand, &fr->datalen);
            fr->encmethods = pvt->encmethods;
            fr->ecx = pvt->ecx;
            fr->mydcx = pvt->mydcx;
            memcpy(fr->semirand, pvt->semirand, sizeof(fr->semirand));
         } else
            ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
      }

      if (now) {
         res = send_packet(fr);
      } else
         res = iax2_transmit(fr);
   } else {
      if (ast_test_flag(pvt, IAX_TRUNK)) {
         iax2_trunk_queue(pvt, fr);
         res = 0;
      } else if (fr->af.frametype == AST_FRAME_VIDEO) {
         /* Video frame have no sequence number */
         fr->oseqno = -1;
         fr->iseqno = -1;
         vh = (struct ast_iax2_video_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_video_hdr));
         vh->zeros = 0;
         vh->callno = htons(0x8000 | fr->callno);
         vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass & 0x1 ? 0x8000 : 0));
         fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
         fr->data = vh;
         fr->retries = -1;
         res = send_packet(fr);        
      } else {
         /* Mini-frames have no sequence number */
         fr->oseqno = -1;
         fr->iseqno = -1;
         /* Mini frame will do */
         mh = (struct ast_iax2_mini_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_mini_hdr));
         mh->callno = htons(fr->callno);
         mh->ts = htons(fr->ts & 0xFFFF);
         fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
         fr->data = mh;
         fr->retries = -1;
         if (pvt->transferring == TRANSFER_MEDIAPASS)
            fr->transfer = 1;
         if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
            if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
               encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen);
            } else
               ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
         }
         res = send_packet(fr);
      }
   }
   return res;
}
static int iax2_sendhtml ( struct ast_channel c,
int  subclass,
const char *  data,
int  datalen 
) [static]

Definition at line 4127 of file chan_iax2.c.

References AST_FRAME_HTML, PTR_TO_CALLNO, send_command_locked(), and ast_channel::tech_pvt.

{
   return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_HTML, subclass, 0, (unsigned char *)data, datalen, -1);
}
static int iax2_sendimage ( struct ast_channel c,
struct ast_frame img 
) [static]
static int iax2_sendtext ( struct ast_channel c,
const char *  text 
) [static]

Definition at line 4115 of file chan_iax2.c.

References AST_FRAME_TEXT, PTR_TO_CALLNO, send_command_locked(), and ast_channel::tech_pvt.

{
   
   return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_TEXT,
      0, 0, (unsigned char *)text, strlen(text) + 1, -1);
}
static int iax2_setoption ( struct ast_channel c,
int  option,
void *  data,
int  datalen 
) [static]

Definition at line 5070 of file chan_iax2.c.

References AST_CONTROL_OPTION, AST_FRAME_CONTROL, ast_free, ast_malloc, ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_FLAG_REQUEST, AST_OPTION_OPRMODE, AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, chan_iax2_pvt::callno, ast_option_header::data, errno, PTR_TO_CALLNO, send_command_locked(), ast_channel::tech_pvt, and wait_for_peercallno().

{
   struct ast_option_header *h;
   int res;

   switch (option) {
   case AST_OPTION_TXGAIN:
   case AST_OPTION_RXGAIN:
      /* these two cannot be sent, because they require a result */
      errno = ENOSYS;
      return -1;
   case AST_OPTION_OPRMODE:
      errno = EINVAL;
      return -1;
   default:
   {
      unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
      struct chan_iax2_pvt *pvt;

      ast_mutex_lock(&iaxsl[callno]);
      pvt = iaxs[callno];

      if (wait_for_peercallno(pvt)) {
         ast_mutex_unlock(&iaxsl[callno]);
         return -1;
      }

      ast_mutex_unlock(&iaxsl[callno]);

      if (!(h = ast_malloc(datalen + sizeof(*h)))) {
         return -1;
      }

      h->flag = AST_OPTION_FLAG_REQUEST;
      h->option = htons(option);
      memcpy(h->data, data, datalen);
      res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL,
                 AST_CONTROL_OPTION, 0, (unsigned char *) h,
                 datalen + sizeof(*h), -1);
      ast_free(h);
      return res;
   }
   }
}
static int iax2_start_transfer ( unsigned short  callno0,
unsigned short  callno1,
int  mediaonly 
) [static]

Definition at line 5154 of file chan_iax2.c.

References iax2_trunk_peer::addr, ast_debug, AST_FRAME_IAX, ast_random(), ast_set_flag, iax_ie_data::buf, IAX_CALLENCRYPTED, IAX_COMMAND_TXREQ, IAX_IE_APPARENT_ADDR, iax_ie_append_addr(), iax_ie_append_int(), iax_ie_append_short(), IAX_IE_CALLNO, IAX_IE_TRANSFERID, IAX_NOTRANSFER, iax_ie_data::pos, send_command(), TRANSFER_BEGIN, TRANSFER_MBEGIN, and chan_iax2_pvt::transferring.

Referenced by iax2_bridge().

{
   int res;
   struct iax_ie_data ied0;
   struct iax_ie_data ied1;
   unsigned int transferid = (unsigned int)ast_random();

   if (IAX_CALLENCRYPTED(iaxs[callno0]) || IAX_CALLENCRYPTED(iaxs[callno1])) {
      ast_debug(1, "transfers are not supported for encrypted calls at this time");
      ast_set_flag(iaxs[callno0], IAX_NOTRANSFER);
      ast_set_flag(iaxs[callno1], IAX_NOTRANSFER);
      return 0;
   }

   memset(&ied0, 0, sizeof(ied0));
   iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr);
   iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno);
   iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transferid);

   memset(&ied1, 0, sizeof(ied1));
   iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &iaxs[callno0]->addr);
   iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[callno0]->peercallno);
   iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transferid);
   
   res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
   if (res)
      return -1;
   res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
   if (res)
      return -1;
   iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
   iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
   return 0;
}
static int iax2_transfer ( struct ast_channel c,
const char *  dest 
) [static]

Definition at line 5408 of file chan_iax2.c.

References ast_copy_string(), ast_debug, AST_FRAME_IAX, iax_ie_data::buf, chan_iax2_pvt::callno, context, IAX_COMMAND_TRANSFER, iax_ie_append_str(), IAX_IE_CALLED_CONTEXT, IAX_IE_CALLED_NUMBER, ast_channel::name, iax_ie_data::pos, PTR_TO_CALLNO, send_command_locked(), and ast_channel::tech_pvt.

{
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   struct iax_ie_data ied = { "", };
   char tmp[256], *context;
   ast_copy_string(tmp, dest, sizeof(tmp));
   context = strchr(tmp, '@');
   if (context) {
      *context = '\0';
      context++;
   }
   iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, tmp);
   if (context)
      iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
   ast_debug(1, "Transferring '%s' to '%s'\n", c->name, dest);
   return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
}
static int iax2_transmit ( struct iax_frame fr) [static]

Definition at line 4087 of file chan_iax2.c.

References AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_sched_thread_poke(), and iax_frame::sentyet.

Referenced by iax2_send().

{
   /* Lock the queue and place this packet at the end */
   /* By setting this to 0, the network thread will send it for us, and
      queue retransmission if necessary */
   fr->sentyet = 0;
   AST_LIST_LOCK(&frame_queue);
   AST_LIST_INSERT_TAIL(&frame_queue, fr, list);
   AST_LIST_UNLOCK(&frame_queue);
   /* Wake up the network and scheduler thread */
   if (netthreadid != AST_PTHREADT_NULL)
      pthread_kill(netthreadid, SIGURG);
   ast_sched_thread_poke(sched);
   return 0;
}
static int iax2_trunk_expired ( struct iax2_trunk_peer tpeer,
struct timeval *  now 
) [inline, static]

Definition at line 8813 of file chan_iax2.c.

References iax2_trunk_peer::trunkact.

Referenced by timing_read().

{
   /* Drop when trunk is about 5 seconds idle */
   if (now->tv_sec > tpeer->trunkact.tv_sec + 5) 
      return 1;
   return 0;
}
static int iax2_trunk_queue ( struct chan_iax2_pvt pvt,
struct iax_frame fr 
) [static]

Definition at line 5817 of file chan_iax2.c.

References iax2_trunk_peer::addr, chan_iax2_pvt::addr, iax_frame::af, ast_debug, ast_inet_ntoa(), ast_log(), ast_mutex_unlock(), ast_realloc, ast_test_flag, ast_tvnow(), ast_iax2_meta_trunk_entry::callno, chan_iax2_pvt::callno, ast_iax2_mini_hdr::callno, iax2_trunk_peer::calls, ast_frame::data, ast_frame::datalen, DEFAULT_TRUNKDATA, f, find_tpeer(), IAX2_TRUNK_PREFACE, IAX_TRUNKTIMESTAMPS, ast_iax2_meta_trunk_entry::len, ast_iax2_meta_trunk_mini::len, iax2_trunk_peer::lock, LOG_WARNING, ast_iax2_meta_trunk_mini::mini, ast_frame::ptr, send_trunk(), chan_iax2_pvt::sockfd, iax2_trunk_peer::trunkdata, iax2_trunk_peer::trunkdataalloc, iax2_trunk_peer::trunkdatalen, iax_frame::ts, and ast_iax2_mini_hdr::ts.

Referenced by iax2_send().

{
   struct ast_frame *f;
   struct iax2_trunk_peer *tpeer;
   void *tmp, *ptr;
   struct timeval now;
   int res; 
   struct ast_iax2_meta_trunk_entry *met;
   struct ast_iax2_meta_trunk_mini *mtm;

   f = &fr->af;
   tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
   if (tpeer) {
      if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
         /* Need to reallocate space */
         if (tpeer->trunkdataalloc < trunkmaxsize) {
            if (!(tmp = ast_realloc(tpeer->trunkdata, tpeer->trunkdataalloc + DEFAULT_TRUNKDATA + IAX2_TRUNK_PREFACE))) {
               ast_mutex_unlock(&tpeer->lock);
               return -1;
            }
            
            tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
            tpeer->trunkdata = tmp;
            ast_debug(1, "Expanded trunk '%s:%d' to %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), tpeer->trunkdataalloc);
         } else {
            ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s:%d\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
            ast_mutex_unlock(&tpeer->lock);
            return -1;
         }
      }

      /* Append to meta frame */
      ptr = tpeer->trunkdata + IAX2_TRUNK_PREFACE + tpeer->trunkdatalen;
      if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS)) {
         mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
         mtm->len = htons(f->datalen);
         mtm->mini.callno = htons(pvt->callno);
         mtm->mini.ts = htons(0xffff & fr->ts);
         ptr += sizeof(struct ast_iax2_meta_trunk_mini);
         tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_mini);
      } else {
         met = (struct ast_iax2_meta_trunk_entry *)ptr;
         /* Store call number and length in meta header */
         met->callno = htons(pvt->callno);
         met->len = htons(f->datalen);
         /* Advance pointers/decrease length past trunk entry header */
         ptr += sizeof(struct ast_iax2_meta_trunk_entry);
         tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_entry);
      }
      /* Copy actual trunk data */
      memcpy(ptr, f->data.ptr, f->datalen);
      tpeer->trunkdatalen += f->datalen;

      tpeer->calls++;

      /* track the largest mtu we actually have sent */
      if (tpeer->trunkdatalen + f->datalen + 4 > trunk_maxmtu) 
         trunk_maxmtu = tpeer->trunkdatalen + f->datalen + 4 ; 

      /* if we have enough for a full MTU, ship it now without waiting */
      if (global_max_trunk_mtu > 0 && tpeer->trunkdatalen + f->datalen + 4 >= global_max_trunk_mtu) {
         now = ast_tvnow();
         res = send_trunk(tpeer, &now); 
         trunk_untimed ++; 
      }

      ast_mutex_unlock(&tpeer->lock);
   }
   return 0;
}
static int iax2_vnak ( int  callno) [static]

Definition at line 8731 of file chan_iax2.c.

References AST_FRAME_IAX, IAX_COMMAND_VNAK, and send_command_immediate().

Referenced by socket_process(), and socket_process_meta().

{
   return send_command_immediate(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_VNAK, 0, NULL, 0, iaxs[callno]->iseqno);
}
static int iax2_write ( struct ast_channel c,
struct ast_frame f 
) [static]

Definition at line 7133 of file chan_iax2.c.

References ast_debug, AST_FRAME_NULL, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, iax2_peer::callno, errno, ast_frame::frametype, iax2_send(), IAX_ALREADYGONE, IAX_QUELCH, IAX_STATE_STARTED, PTR_TO_CALLNO, and ast_channel::tech_pvt.

{
   unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
   int res = -1;
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
   /* If there's an outstanding error, return failure now */
      if (!iaxs[callno]->error) {
         if (ast_test_flag(iaxs[callno], IAX_ALREADYGONE))
            res = 0;
            /* Don't waste bandwidth sending null frames */
         else if (f->frametype == AST_FRAME_NULL)
            res = 0;
         else if ((f->frametype == AST_FRAME_VOICE) && ast_test_flag(iaxs[callno], IAX_QUELCH))
            res = 0;
         else if (!ast_test_flag(&iaxs[callno]->state, IAX_STATE_STARTED))
            res = 0;
         else
         /* Simple, just queue for transmission */
            res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0);
      } else {
         ast_debug(1, "Write error: %s\n", strerror(errno));
      }
   }
   /* If it's already gone, just return */
   ast_mutex_unlock(&iaxsl[callno]);
   return res;
}
static int iax_check_version ( char *  dev) [static]

Definition at line 3005 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_iax2_firmware_header::devname, iax_firmware::fwh, and ast_iax2_firmware_header::version.

Referenced by update_registry().

{
   int res = 0;
   struct iax_firmware *cur = NULL;

   if (ast_strlen_zero(dev))
      return 0;

   AST_LIST_LOCK(&firmwares);
   AST_LIST_TRAVERSE(&firmwares, cur, list) {
      if (!strcmp(dev, (char *)cur->fwh->devname)) {
         res = ntohs(cur->fwh->version);
         break;
      }
   }
   AST_LIST_UNLOCK(&firmwares);

   return res;
}
static void iax_debug_output ( const char *  data) [static]

Definition at line 1063 of file chan_iax2.c.

References ast_verbose().

Referenced by load_module().

{
   if (iaxdebug)
      ast_verbose("%s", data);
}
static void iax_error_output ( const char *  data) [static]

Definition at line 1069 of file chan_iax2.c.

References ast_log(), and LOG_WARNING.

Referenced by load_module().

{
   ast_log(LOG_WARNING, "%s", data);
}
static int iax_firmware_append ( struct iax_ie_data ied,
const unsigned char *  dev,
unsigned int  desc 
) [static]

Definition at line 3025 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_iax2_firmware_header::data, ast_iax2_firmware_header::datalen, ast_iax2_firmware_header::devname, iax_firmware::fwh, iax_ie_append(), iax_ie_append_int(), iax_ie_append_raw(), IAX_IE_FWBLOCKDATA, and IAX_IE_FWBLOCKDESC.

Referenced by socket_process().

{
   int res = -1;
   unsigned int bs = desc & 0xff;
   unsigned int start = (desc >> 8) & 0xffffff;
   unsigned int bytes;
   struct iax_firmware *cur;

   if (ast_strlen_zero((char *)dev) || !bs)
      return -1;

   start *= bs;
   
   AST_LIST_LOCK(&firmwares);
   AST_LIST_TRAVERSE(&firmwares, cur, list) {
      if (strcmp((char *)dev, (char *)cur->fwh->devname))
         continue;
      iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
      if (start < ntohl(cur->fwh->datalen)) {
         bytes = ntohl(cur->fwh->datalen) - start;
         if (bytes > bs)
            bytes = bs;
         iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);
      } else {
         bytes = 0;
         iax_ie_append(ied, IAX_IE_FWBLOCKDATA);
      }
      if (bytes == bs)
         res = 0;
      else
         res = 1;
      break;
   }
   AST_LIST_UNLOCK(&firmwares);

   return res;
}
static void iax_outputframe ( struct iax_frame f,
struct ast_iax2_full_hdr fhi,
int  rx,
struct sockaddr_in *  sin,
int  datalen 
) [static]

Definition at line 1046 of file chan_iax2.c.

References debugaddr, and iax_showframe().

Referenced by iax2_send(), raw_hangup(), and socket_process().

{
   if (iaxdebug ||
       (sin && debugaddr.sin_addr.s_addr && 
        (!ntohs(debugaddr.sin_port) ||
         debugaddr.sin_port == sin->sin_port) &&
        debugaddr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
      if (iaxdebug) {
         iax_showframe(f, fhi, rx, sin, datalen);
      } else {
         iaxdebug = 1;
         iax_showframe(f, fhi, rx, sin, datalen);
         iaxdebug = 0;
      }
   }
}
static int iax_park ( struct ast_channel chan1,
struct ast_channel chan2 
) [static]

Definition at line 8975 of file chan_iax2.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_copy_string(), ast_do_masquerade(), ast_free, ast_hangup(), ast_log(), ast_pthread_create_detached_background, AST_STATE_DOWN, iax_dual::chan1, iax_dual::chan2, ast_channel::context, ast_channel::exten, iax_park_thread(), LOG_WARNING, ast_channel::name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.

Referenced by socket_process().

{
   struct iax_dual *d;
   struct ast_channel *chan1m, *chan2m;
   pthread_t th;
   chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->amaflags, "Parking/%s", chan1->name);
   chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->amaflags, "IAXPeer/%s",chan2->name);
   if (chan2m && chan1m) {
      /* Make formats okay */
      chan1m->readformat = chan1->readformat;
      chan1m->writeformat = chan1->writeformat;
      ast_channel_masquerade(chan1m, chan1);
      /* Setup the extensions and such */
      ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
      ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
      chan1m->priority = chan1->priority;
      
      /* We make a clone of the peer channel too, so we can play
         back the announcement */
      /* Make formats okay */
      chan2m->readformat = chan2->readformat;
      chan2m->writeformat = chan2->writeformat;
      ast_channel_masquerade(chan2m, chan2);
      /* Setup the extensions and such */
      ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
      ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
      chan2m->priority = chan2->priority;
      if (ast_do_masquerade(chan2m)) {
         ast_log(LOG_WARNING, "Masquerade failed :(\n");
         ast_hangup(chan2m);
         return -1;
      }
   } else {
      if (chan1m)
         ast_hangup(chan1m);
      if (chan2m)
         ast_hangup(chan2m);
      return -1;
   }
   if ((d = ast_calloc(1, sizeof(*d)))) {
      d->chan1 = chan1m;
      d->chan2 = chan2m;
      if (!ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d)) {
         return 0;
      }
      ast_free(d);
   }
   return -1;
}
static void* iax_park_thread ( void *  stuff) [static]

Definition at line 8955 of file chan_iax2.c.

References ast_free, ast_frfree, ast_hangup(), ast_log(), ast_park_call(), ast_read(), iax_dual::chan1, iax_dual::chan2, ext, f, and LOG_NOTICE.

Referenced by iax_park().

{
   struct ast_channel *chan1, *chan2;
   struct iax_dual *d;
   struct ast_frame *f;
   int ext;
   int res;
   d = stuff;
   chan1 = d->chan1;
   chan2 = d->chan2;
   ast_free(d);
   f = ast_read(chan1);
   if (f)
      ast_frfree(f);
   res = ast_park_call(chan1, chan2, 0, &ext);
   ast_hangup(chan2);
   ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
   return NULL;
}
static struct iax_frame* iaxfrdup2 ( struct iax_frame fr) [static, read]

Definition at line 1842 of file chan_iax2.c.

References iax_frame::af, iax_frame::afdatalen, iax_frame::cacheable, ast_frame::datalen, DIRECTION_INGRESS, iax_frame_new(), and iax_frame_wrap().

Referenced by socket_process(), and socket_process_meta().

{
   struct iax_frame *new = iax_frame_new(DIRECTION_INGRESS, fr->af.datalen, fr->cacheable);
   if (new) {
      size_t afdatalen = new->afdatalen;
      memcpy(new, fr, sizeof(*new));
      iax_frame_wrap(new, &fr->af);
      new->afdatalen = afdatalen;
      new->data = NULL;
      new->datalen = 0;
      new->direction = DIRECTION_INGRESS;
      new->retrans = -1;
   }
   return new;
}
static void insert_idle_thread ( struct iax2_thread thread) [static]
static void jb_debug_output ( const char *  fmt,
  ... 
) [static]

Definition at line 1098 of file chan_iax2.c.

References ast_verbose().

Referenced by handle_cli_iax2_set_debug_jb().

{
   va_list args;
   char buf[1024];

   va_start(args, fmt);
   vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);

   ast_verbose("%s", buf);
}
static void jb_error_output ( const char *  fmt,
  ... 
) [static]

Definition at line 1074 of file chan_iax2.c.

References ast_log(), and LOG_ERROR.

Referenced by handle_cli_iax2_set_debug_jb(), and load_module().

{
   va_list args;
   char buf[1024];

   va_start(args, fmt);
   vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);

   ast_log(LOG_ERROR, "%s", buf);
}
static void jb_warning_output ( const char *  fmt,
  ... 
) [static]

Definition at line 1086 of file chan_iax2.c.

References ast_log(), and LOG_WARNING.

Referenced by handle_cli_iax2_set_debug_jb(), and load_module().

{
   va_list args;
   char buf[1024];

   va_start(args, fmt);
   vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);

   ast_log(LOG_WARNING, "%s", buf);
}
static int load_module ( void  ) [static]

Load IAX2 module, load configuraiton ---.

Definition at line 13860 of file chan_iax2.c.

References __unload_module(), ao2_callback, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_manager_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init(), ast_netsock_init(), ast_netsock_list_alloc(), ast_random(), ast_realtime_require_field(), ast_register_application_xml, ast_register_switch(), ast_sched_thread_create(), ast_sched_thread_destroy(), ast_timer_close(), ast_timer_open(), ast_timer_set_rate(), ast_verb, config, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, iax2_do_register(), iax2_poke_peer_cb(), iax2_prov_app(), iax_debug_output(), iax_error_output(), iax_provision_reload(), iax_set_error(), iax_set_output(), io_context_create(), io_context_destroy(), jb_error_output(), jb_setoutput(), jb_warning_output(), load_objects(), LOG_ERROR, manager_iax2_show_netstats(), manager_iax2_show_peer_list(), manager_iax2_show_peers(), manager_iax2_show_registry(), peer_set_sock_cb(), reload_firmware(), RQ_CHAR, RQ_UINTEGER2, SENTINEL, set_config(), and start_network_thread().

{
   static const char config[] = "iax.conf";
   int x = 0;
   struct iax2_registry *reg = NULL;

   if (load_objects()) {
      return AST_MODULE_LOAD_FAILURE;
   }

   memset(iaxs, 0, sizeof(iaxs));

   for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
      ast_mutex_init(&iaxsl[x]);
   }

   if (!(sched = ast_sched_thread_create())) {
      ast_log(LOG_ERROR, "Failed to create scheduler thread\n");
      return AST_MODULE_LOAD_FAILURE;
   }

   if (!(io = io_context_create())) {
      ast_log(LOG_ERROR, "Failed to create I/O context\n");
      sched = ast_sched_thread_destroy(sched);
      return AST_MODULE_LOAD_FAILURE;
   }

   if (!(netsock = ast_netsock_list_alloc())) {
      ast_log(LOG_ERROR, "Failed to create netsock list\n");
      io_context_destroy(io);
      sched = ast_sched_thread_destroy(sched);
      return AST_MODULE_LOAD_FAILURE;
   }
   ast_netsock_init(netsock);
   
   outsock = ast_netsock_list_alloc();
   if (!outsock) {
      ast_log(LOG_ERROR, "Could not allocate outsock list.\n");
      io_context_destroy(io);
      sched = ast_sched_thread_destroy(sched);
      return AST_MODULE_LOAD_FAILURE;
   }
   ast_netsock_init(outsock);

   randomcalltokendata = ast_random();

   iax_set_output(iax_debug_output);
   iax_set_error(iax_error_output);
   jb_setoutput(jb_error_output, jb_warning_output, NULL);
   
   if ((timer = ast_timer_open())) {
      ast_timer_set_rate(timer, trunkfreq);
   }

   if (set_config(config, 0) == -1) {
      if (timer) {
         ast_timer_close(timer);
      }
      return AST_MODULE_LOAD_DECLINE;
   }

   ast_cli_register_multiple(cli_iax2, ARRAY_LEN(cli_iax2));

   ast_register_application_xml(papp, iax2_prov_app);

   ast_custom_function_register(&iaxpeer_function);
   ast_custom_function_register(&iaxvar_function);

   ast_manager_register( "IAXpeers", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peers, "List IAX Peers" );
   ast_manager_register( "IAXpeerlist", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peer_list, "List IAX Peers" );
   ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" );
   ast_manager_register( "IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry, "Show IAX registrations");

   if (ast_channel_register(&iax2_tech)) {
      ast_log(LOG_ERROR, "Unable to register channel class %s\n", "IAX2");
      __unload_module();
      return AST_MODULE_LOAD_FAILURE;
   }

   if (ast_register_switch(&iax2_switch)) {
      ast_log(LOG_ERROR, "Unable to register IAX switch\n");
   }

   if (start_network_thread()) {
      ast_log(LOG_ERROR, "Unable to start network thread\n");
      __unload_module();
      return AST_MODULE_LOAD_FAILURE;
   } else {
      ast_verb(2, "IAX Ready and Listening\n");
   }

   AST_LIST_LOCK(&registrations);
   AST_LIST_TRAVERSE(&registrations, reg, entry)
      iax2_do_register(reg);
   AST_LIST_UNLOCK(&registrations); 
   
   ao2_callback(peers, 0, peer_set_sock_cb, NULL);
   ao2_callback(peers, 0, iax2_poke_peer_cb, NULL);


   reload_firmware(0);
   iax_provision_reload(0);

   ast_realtime_require_field("iaxpeers", "name", RQ_CHAR, 10, "ipaddr", RQ_CHAR, 15, "port", RQ_UINTEGER2, 5, "regseconds", RQ_UINTEGER2, 6, SENTINEL);

   return AST_MODULE_LOAD_SUCCESS;
}
static int load_objects ( void  ) [static]

Definition at line 13801 of file chan_iax2.c.

References addr_range_cmp_cb(), addr_range_hash_cb(), ao2_container_alloc, ao2_ref, AST_MODULE_LOAD_FAILURE, create_callno_pools(), IAX_MAX_CALLS, MAX_PEER_BUCKETS, MAX_USER_BUCKETS, peer_cmp_cb(), peer_hash_cb(), peercnt_cmp_cb(), peercnt_hash_cb(), pvt_cmp_cb(), pvt_hash_cb(), transfercallno_pvt_cmp_cb(), transfercallno_pvt_hash_cb(), user_cmp_cb(), and user_hash_cb().

Referenced by load_module().

{
   peers = users = iax_peercallno_pvts = iax_transfercallno_pvts = NULL;
   peercnts = callno_limits = calltoken_ignores = callno_pool = callno_pool_trunk = NULL;

   if (!(peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb))) {
      goto container_fail;
   } else if (!(users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb))) {
      goto container_fail;
   } else if (!(iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb))) {
      goto container_fail;
   } else if (!(iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb))) {
      goto container_fail;
   } else if (!(peercnts = ao2_container_alloc(MAX_PEER_BUCKETS, peercnt_hash_cb, peercnt_cmp_cb))) {
      goto container_fail;
   } else if (!(callno_limits = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
      goto container_fail;
   } else if (!(calltoken_ignores = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
      goto container_fail;
   } else if (create_callno_pools()) {
      goto container_fail;
   }

   return 0;

container_fail:
   if (peers) {
      ao2_ref(peers, -1);
   }
   if (users) {
      ao2_ref(users, -1);
   }
   if (iax_peercallno_pvts) {
      ao2_ref(iax_peercallno_pvts, -1);
   }
   if (iax_transfercallno_pvts) {
      ao2_ref(iax_transfercallno_pvts, -1);
   }
   if (peercnts) {
      ao2_ref(peercnts, -1);
   }
   if (callno_limits) {
      ao2_ref(callno_limits, -1);
   }
   if (calltoken_ignores) {
      ao2_ref(calltoken_ignores, -1);
   }
   if (callno_pool) {
      ao2_ref(callno_pool, -1);
   }
   if (callno_pool_trunk) {
      ao2_ref(callno_pool_trunk, -1);
   }
   return AST_MODULE_LOAD_FAILURE;
}
static void lock_both ( unsigned short  callno0,
unsigned short  callno1 
) [static]

Definition at line 5189 of file chan_iax2.c.

References ast_mutex_lock(), ast_mutex_trylock(), and DEADLOCK_AVOIDANCE.

Referenced by iax2_bridge().

{
   ast_mutex_lock(&iaxsl[callno0]);
   while (ast_mutex_trylock(&iaxsl[callno1])) {
      DEADLOCK_AVOIDANCE(&iaxsl[callno0]);
   }
}
static void log_jitterstats ( unsigned short  callno) [static]

Definition at line 9098 of file chan_iax2.c.

References ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, jb_info::current, iax_rr::delay, iax_rr::dropped, EVENT_FLAG_REPORTING, jb_info::frames_dropped, jb_info::frames_in, jb_info::frames_lost, jb_info::frames_ooo, IAX_USEJITTERBUF, ast_channel::jb, jb_getinfo(), iax_rr::jitter, jb_info::jitter, iax_rr::losscnt, iax_rr::losspct, jb_info::losspct, manager_event, jb_info::min, iax_rr::ooo, iax_rr::packets, chan_iax2_pvt::pingtime, and chan_iax2_pvt::remote_rr.

Referenced by socket_process().

{
   int localjitter = -1, localdelay = 0, locallost = -1, locallosspct = -1, localdropped = 0, localooo = -1, localpackets = -1;
   jb_info jbinfo;

   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno] && iaxs[callno]->owner && iaxs[callno]->owner->name) {
      if(ast_test_flag(iaxs[callno], IAX_USEJITTERBUF)) {
         jb_getinfo(iaxs[callno]->jb, &jbinfo);
         localjitter = jbinfo.jitter;
         localdelay = jbinfo.current - jbinfo.min;
         locallost = jbinfo.frames_lost;
         locallosspct = jbinfo.losspct/1000;
         localdropped = jbinfo.frames_dropped;
         localooo = jbinfo.frames_ooo;
         localpackets = jbinfo.frames_in;
      }
      ast_debug(3, "JB STATS:%s ping=%d ljitterms=%d ljbdelayms=%d ltotlost=%d lrecentlosspct=%d ldropped=%d looo=%d lrecvd=%d rjitterms=%d rjbdelayms=%d rtotlost=%d rrecentlosspct=%d rdropped=%d rooo=%d rrecvd=%d\n",
         iaxs[callno]->owner->name,
         iaxs[callno]->pingtime,
         localjitter,
         localdelay,
         locallost,
         locallosspct,
         localdropped,
         localooo,
         localpackets,
         iaxs[callno]->remote_rr.jitter,
         iaxs[callno]->remote_rr.delay,
         iaxs[callno]->remote_rr.losscnt,
         iaxs[callno]->remote_rr.losspct/1000,
         iaxs[callno]->remote_rr.dropped,
         iaxs[callno]->remote_rr.ooo,
         iaxs[callno]->remote_rr.packets);
      manager_event(EVENT_FLAG_REPORTING, "JitterBufStats", "Owner: %s\r\nPing: %d\r\nLocalJitter: %d\r\nLocalJBDelay: %d\r\nLocalTotalLost: %d\r\nLocalLossPercent: %d\r\nLocalDropped: %d\r\nLocalooo: %d\r\nLocalReceived: %d\r\nRemoteJitter: %d\r\nRemoteJBDelay: %d\r\nRemoteTotalLost: %d\r\nRemoteLossPercent: %d\r\nRemoteDropped: %d\r\nRemoteooo: %d\r\nRemoteReceived: %d\r\n",
         iaxs[callno]->owner->name,
         iaxs[callno]->pingtime,
         localjitter,
         localdelay,
         locallost,
         locallosspct,
         localdropped,
         localooo,
         localpackets,
         iaxs[callno]->remote_rr.jitter,
         iaxs[callno]->remote_rr.delay,
         iaxs[callno]->remote_rr.losscnt,
         iaxs[callno]->remote_rr.losspct/1000,
         iaxs[callno]->remote_rr.dropped,
         iaxs[callno]->remote_rr.ooo,
         iaxs[callno]->remote_rr.packets);
   }
   ast_mutex_unlock(&iaxsl[callno]);
}
static int make_trunk ( unsigned short  callno,
int  locked 
) [static]

Note:
We delete these before switching the slot, because if they fire in the meantime, they will generate a warning.

Definition at line 1922 of file chan_iax2.c.

References ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_thread_del, chan_iax2_pvt::callno, callno_entry::callno, chan_iax2_pvt::callno_entry, get_unused_callno(), iax2_sched_add(), chan_iax2_pvt::lagid, LOG_WARNING, MIN_REUSE_TIME, chan_iax2_pvt::pingid, replace_callno(), send_lagrq(), send_ping(), TRUNK_CALL_START, update_max_nontrunk(), update_max_trunk(), and callno_entry::validated.

Referenced by iax2_request(), and socket_process().

{
   int x;
   int res= 0;
   struct callno_entry *callno_entry;
   if (iaxs[callno]->oseqno) {
      ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");
      return -1;
   }
   if (callno & TRUNK_CALL_START) {
      ast_log(LOG_WARNING, "Call %d is already a trunk\n", callno);
      return -1;
   }

   if (!(callno_entry = get_unused_callno(1, iaxs[callno]->callno_entry->validated))) {
      ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
      return -1;
   }

   x = callno_entry->callno;
   ast_mutex_lock(&iaxsl[x]);

   /*!
    * \note We delete these before switching the slot, because if
    * they fire in the meantime, they will generate a warning.
    */
   ast_sched_thread_del(sched, iaxs[callno]->pingid);
   ast_sched_thread_del(sched, iaxs[callno]->lagid);
   iaxs[x] = iaxs[callno];
   iaxs[x]->callno = x;

   /* since we copied over the pvt from a different callno, make sure the old entry is replaced
    * before assigning the new one */
   if (iaxs[x]->callno_entry) {
      iax2_sched_add(sched, MIN_REUSE_TIME * 1000, replace_callno, iaxs[x]->callno_entry);
   }
   iaxs[x]->callno_entry = callno_entry;

   iaxs[callno] = NULL;
   /* Update the two timers that should have been started */
   iaxs[x]->pingid = iax2_sched_add(sched, 
      ping_time * 1000, send_ping, (void *)(long)x);
   iaxs[x]->lagid = iax2_sched_add(sched, 
      lagrq_time * 1000, send_lagrq, (void *)(long)x);

   if (locked)
      ast_mutex_unlock(&iaxsl[callno]);
   res = x;
   if (!locked)
      ast_mutex_unlock(&iaxsl[x]);

   ast_debug(1, "Made call %d into trunk call %d\n", callno, x);
   /* We move this call from a non-trunked to a trunked call */
   update_max_trunk();
   update_max_nontrunk();
   return res;
}
static int manager_iax2_show_netstats ( struct mansession s,
const struct message m 
) [static]

Definition at line 6649 of file chan_iax2.c.

References ast_cli_netstats(), astman_append(), and RESULT_SUCCESS.

Referenced by load_module().

{
   ast_cli_netstats(s, -1, 0);
   astman_append(s, "\r\n");
   return RESULT_SUCCESS;
}
static int manager_iax2_show_peer_list ( struct mansession s,
const struct message m 
) [static]

callback to display iax peers in manager format

Definition at line 6701 of file chan_iax2.c.

References iax2_peer::addr, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_copy_string(), ast_inet_ntoa(), ast_str_alloca, ast_str_buffer(), ast_strlen_zero(), ast_test_flag, astman_append(), astman_get_header(), iax2_peer::encmethods, encmethods_to_str(), IAX_DYNAMIC, IAX_TRUNK, iax2_peer::mask, iax2_peer::name, peer_status(), peer_unref(), RESULT_SUCCESS, status, and iax2_peer::username.

Referenced by load_module().

{
   struct iax2_peer *peer = NULL;
   int peer_count = 0;
   char nm[20];
   char status[20];
   const char *id = astman_get_header(m,"ActionID");
   char idtext[256] = "";
   struct ast_str *encmethods = ast_str_alloca(256);
   struct ao2_iterator i;

   if (!ast_strlen_zero(id))
      snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);

   astman_append(s, "Response: Success\r\n%sMessage: IAX Peer status list will follow\r\n\r\n", idtext);


   i = ao2_iterator_init(peers, 0);
   for (peer = ao2_iterator_next(&i); peer; peer_unref(peer), peer = ao2_iterator_next(&i)) {
      encmethods_to_str(peer->encmethods, encmethods);
      astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
      if (!ast_strlen_zero(peer->username)) {
         astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username);
      } else {
         astman_append(s, "ObjectName: %s\r\n", peer->name);
      }
      astman_append(s, "ChanObjectType: peer\r\n");
      astman_append(s, "IPaddress: %s\r\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "-none-");
      ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
      astman_append(s, "Mask: %s\r\n", nm);
      astman_append(s, "Port: %d\r\n", ntohs(peer->addr.sin_port));
      astman_append(s, "Dynamic: %s\r\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes" : "No");
      astman_append(s, "Trunk: %s\r\n", ast_test_flag(peer, IAX_TRUNK) ? "Yes" : "No");
      astman_append(s, "Encryption: %s\r\n", peer->encmethods ? ast_str_buffer(encmethods) : "No");
      peer_status(peer, status, sizeof(status));
      astman_append(s, "Status: %s\r\n\r\n", status);
      peer_count++;
   }
   ao2_iterator_destroy(&i);

   astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
   return RESULT_SUCCESS;
}
static int manager_iax2_show_peers ( struct mansession s,
const struct message m 
) [static]

callback to display iax peers in manager

Definition at line 6688 of file chan_iax2.c.

References __iax2_show_peers(), ast_strlen_zero(), astman_get_header(), and astman_send_ack().

Referenced by load_module().

{
   char *a[] = { "iax2", "show", "users" };
   const char *id = astman_get_header(m,"ActionID");
   char idtext[256] = "";

   if (!ast_strlen_zero(id))
      snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
   astman_send_ack(s, m, "Peer status list will follow");
   return __iax2_show_peers(1, -1, s, 3, a );
} 
static int manager_iax2_show_registry ( struct mansession s,
const struct message m 
) [static]

Definition at line 6809 of file chan_iax2.c.

References iax2_registry::addr, ast_copy_string(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_listack(), iax2_registry::dnsmgr, iax2_registry::refresh, iax2_registry::regstate, regstate2str(), total, iax2_registry::us, and iax2_registry::username.

Referenced by load_module().

{
   const char *id = astman_get_header(m, "ActionID");
   struct iax2_registry *reg = NULL;
   char idtext[256] = "";
   char host[80] = "";
   char perceived[80] = "";
   int total = 0;

   if (!ast_strlen_zero(id))
      snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);

   astman_send_listack(s, m, "Registrations will follow", "start");

   AST_LIST_LOCK(&registrations);
   AST_LIST_TRAVERSE(&registrations, reg, entry) {
      snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(reg->addr.sin_addr), ntohs(reg->addr.sin_port));
      
      if (reg->us.sin_addr.s_addr) {
         snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
      } else {
         ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
      }
      
      astman_append(s,
         "Event: RegistryEntry\r\n"
         "%s"
         "Host: %s\r\n"
         "DNSmanager: %s\r\n"
         "Username: %s\r\n"
         "Perceived: %s\r\n"
         "Refresh: %d\r\n"
         "State: %s\r\n"
         "\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived, 
         reg->refresh, regstate2str(reg->regstate));

      total++;
   }
   AST_LIST_UNLOCK(&registrations);

   astman_append(s,
      "Event: RegistrationsComplete\r\n"
      "EventList: Complete\r\n"
      "ListItems: %d\r\n"
      "%s"
      "\r\n", total, idtext);
   
   return 0;
}
static int match ( struct sockaddr_in *  sin,
unsigned short  callno,
unsigned short  dcallno,
const struct chan_iax2_pvt cur,
int  check_dcallno 
) [static]

Definition at line 1871 of file chan_iax2.c.

References chan_iax2_pvt::addr, chan_iax2_pvt::callno, chan_iax2_pvt::peercallno, chan_iax2_pvt::transfer, TRANSFER_MEDIAPASS, chan_iax2_pvt::transfercallno, and chan_iax2_pvt::transferring.

Referenced by __ao2_callback(), __find_callno(), ast_parse_device_state(), check_blacklist(), find_by_name(), find_command(), handle_updates(), lua_find_extension(), pbx_find_extension(), pvt_cmp_cb(), realtime_switch_common(), and transfercallno_pvt_cmp_cb().

{
   if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
      (cur->addr.sin_port == sin->sin_port)) {
      /* This is the main host */
      if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
          (check_dcallno ? dcallno == cur->callno : 1) ) {
         /* That's us.  Be sure we keep track of the peer call number */
         return 1;
      }
   }
   if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
       (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
      /* We're transferring */
      if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
         return 1;
   }
   return 0;
}
static void memcpy_decrypt ( unsigned char *  dst,
const unsigned char *  src,
int  len,
ast_aes_decrypt_key dcx 
) [static]

Definition at line 5916 of file chan_iax2.c.

References ast_aes_decrypt, ast_log(), len(), and LOG_WARNING.

Referenced by decode_frame().

{
#if 0
   /* Debug with "fake encryption" */
   int x;
   if (len % 16)
      ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
   for (x=0;x<len;x++)
      dst[x] = src[x] ^ 0xff;
#else 
   unsigned char lastblock[16] = { 0 };
   int x;
   while(len > 0) {
      ast_aes_decrypt(src, dst, dcx);
      for (x=0;x<16;x++)
         dst[x] ^= lastblock[x];
      memcpy(lastblock, src, sizeof(lastblock));
      dst += 16;
      src += 16;
      len -= 16;
   }
#endif
}
static void memcpy_encrypt ( unsigned char *  dst,
const unsigned char *  src,
int  len,
ast_aes_encrypt_key ecx 
) [static]

Definition at line 5940 of file chan_iax2.c.

References ast_aes_encrypt, ast_log(), len(), and LOG_WARNING.

Referenced by encrypt_frame().

{
#if 0
   /* Debug with "fake encryption" */
   int x;
   if (len % 16)
      ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
   for (x=0;x<len;x++)
      dst[x] = src[x] ^ 0xff;
#else
   unsigned char curblock[16] = { 0 };
   int x;
   while(len > 0) {
      for (x=0;x<16;x++)
         curblock[x] ^= src[x];
      ast_aes_encrypt(curblock, dst, ecx);
      memcpy(curblock, dst, sizeof(curblock)); 
      dst += 16;
      src += 16;
      len -= 16;
   }
#endif
}
static void merge_encryption ( struct chan_iax2_pvt p,
unsigned int  enc 
) [static]

Definition at line 7475 of file chan_iax2.c.

References chan_iax2_pvt::encmethods, IAX_ENCRYPT_AES128, IAX_ENCRYPT_KEYROTATE, and chan_iax2_pvt::keyrotateid.

Referenced by authenticate_reply(), and socket_process().

{
   /* Select exactly one common encryption if there are any */
   p->encmethods &= enc;
   if (p->encmethods) {
      if (!(p->encmethods & IAX_ENCRYPT_KEYROTATE)){ /* if key rotation is not supported, turn off keyrotation. */
         p->keyrotateid = -2;
      }
      if (p->encmethods & IAX_ENCRYPT_AES128)
         p->encmethods = IAX_ENCRYPT_AES128;
      else
         p->encmethods = 0;
   }
}
static void mwi_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 1217 of file chan_iax2.c.

Referenced by build_peer().

{
   /* The MWI subscriptions exist just so the core knows we care about those
    * mailboxes.  However, we just grab the events out of the cache when it
    * is time to send MWI, since it is only sent with a REGACK. */
}
static void* network_thread ( void *  ignore) [static]

Definition at line 11686 of file chan_iax2.c.

References ast_debug, ast_io_add(), AST_IO_IN, AST_IO_PRI, ast_io_wait(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_mutex_trylock(), ast_mutex_unlock(), ast_timer_fd(), attempt_transmit(), iax_frame::callno, f, iax2_sched_add(), iax_frame_free(), iax_frame::retrans, iax_frame::retries, iax_frame::retrytime, send_packet(), iax_frame::sentyet, and timing_read().

Referenced by start_network_thread().

{
   /* Our job is simple: Send queued messages, retrying if necessary.  Read frames 
      from the network, and queue them for delivery to the channels */
   int res, count, wakeup;
   struct iax_frame *f;

   if (timer)
      ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
   
   for(;;) {
      pthread_testcancel();

      /* Go through the queue, sending messages which have not yet been
         sent, and scheduling retransmissions if appropriate */
      AST_LIST_LOCK(&frame_queue);
      count = 0;
      wakeup = -1;
      AST_LIST_TRAVERSE_SAFE_BEGIN(&frame_queue, f, list) {
         if (f->sentyet)
            continue;
         
         /* Try to lock the pvt, if we can't... don't fret - defer it till later */
         if (ast_mutex_trylock(&iaxsl[f->callno])) {
            wakeup = 1;
            continue;
         }

         f->sentyet = 1;

         if (iaxs[f->callno]) {
            send_packet(f);
            count++;
         } 

         ast_mutex_unlock(&iaxsl[f->callno]);

         if (f->retries < 0) {
            /* This is not supposed to be retransmitted */
            AST_LIST_REMOVE_CURRENT(list);
            /* Free the iax frame */
            iax_frame_free(f);
         } else {
            /* We need reliable delivery.  Schedule a retransmission */
            f->retries++;
            f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);
         }
      }
      AST_LIST_TRAVERSE_SAFE_END;
      AST_LIST_UNLOCK(&frame_queue);

      pthread_testcancel();
      if (count >= 20)
         ast_debug(1, "chan_iax2: Sent %d queued outbound frames all at once\n", count);

      /* Now do the IO, and run scheduled tasks */
      res = ast_io_wait(io, wakeup);
      if (res >= 0) {
         if (res >= 20)
            ast_debug(1, "chan_iax2: ast_io_wait ran %d I/Os all at once\n", res);
      }
   }
   return NULL;
}
static struct chan_iax2_pvt* new_iax ( struct sockaddr_in *  sin,
const char *  host 
) [static, read]
static void parse_dial_string ( char *  data,
struct parsed_dial_string pds 
) [static]

Parses an IAX dial string into its component parts.

Parameters:
datathe string to be parsed
pdspointer to a struct parsed_dial_string to be filled in
Returns:
nothing

This function parses the string and fills the structure with pointers to its component parts. The input string will be modified.

Note:
This function supports both plaintext passwords and RSA key names; if the password string is formatted as '[keyname]', then the keyname will be placed into the key field, and the password field will be set to NULL.
The dial string format is: [username[:password]@]peer[:port][/exten[@context]][/options]

Definition at line 4770 of file chan_iax2.c.

References ast_strip_quoted(), ast_strlen_zero(), parsed_dial_string::context, parsed_dial_string::exten, parsed_dial_string::key, parsed_dial_string::options, parsed_dial_string::password, parsed_dial_string::peer, parsed_dial_string::port, strsep(), and parsed_dial_string::username.

Referenced by cache_get_callno_locked(), iax2_call(), iax2_devicestate(), and iax2_request().

{
   if (ast_strlen_zero(data))
      return;

   pds->peer = strsep(&data, "/");
   pds->exten = strsep(&data, "/");
   pds->options = data;

   if (pds->exten) {
      data = pds->exten;
      pds->exten = strsep(&data, "@");
      pds->context = data;
   }

   if (strchr(pds->peer, '@')) {
      data = pds->peer;
      pds->username = strsep(&data, "@");
      pds->peer = data;
   }

   if (pds->username) {
      data = pds->username;
      pds->username = strsep(&data, ":");
      pds->password = data;
   }

   data = pds->peer;
   pds->peer = strsep(&data, ":");
   pds->port = data;

   /* check for a key name wrapped in [] in the secret position, if found,
      move it to the key field instead
   */
   if (pds->password && (pds->password[0] == '[')) {
      pds->key = ast_strip_quoted(pds->password, "[", "]");
      pds->password = NULL;
   }
}
static int peer_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]
Note:
The only member of the peer passed here guaranteed to be set is the name field

Definition at line 1548 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, and iax2_peer::name.

Referenced by load_objects().

{
   struct iax2_peer *peer = obj, *peer2 = arg;

   return !strcmp(peer->name, peer2->name) ? CMP_MATCH | CMP_STOP : 0;
}
static int peer_delme_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 12449 of file chan_iax2.c.

References ast_set_flag, and IAX_DELME.

Referenced by delete_users().

{
   struct iax2_peer *peer = obj;

   ast_set_flag(peer, IAX_DELME);

   return 0;
}
static void peer_destructor ( void *  obj) [static]
static int peer_hash_cb ( const void *  obj,
const int  flags 
) [static]
Note:
The only member of the peer passed here guaranteed to be set is the name field

Definition at line 1538 of file chan_iax2.c.

References ast_str_hash(), and iax2_peer::name.

Referenced by load_objects().

{
   const struct iax2_peer *peer = obj;

   return ast_str_hash(peer->name);
}
static struct iax2_peer* peer_ref ( struct iax2_peer peer) [static, read]
static int peer_set_sock_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 13755 of file chan_iax2.c.

References defaultsockfd, and iax2_peer::sockfd.

Referenced by load_module().

{
   struct iax2_peer *peer = obj;

   if (peer->sockfd < 0)
      peer->sockfd = defaultsockfd;

   return 0;
}
static int peer_set_srcaddr ( struct iax2_peer peer,
const char *  srcaddr 
) [static]

Parse the "sourceaddress" value, lookup in netsock list and set peer's sockfd. Defaults to defaultsockfd if not found.

Definition at line 11836 of file chan_iax2.c.

References iax2_trunk_peer::addr, ast_debug, ast_get_ip(), ast_log(), ast_netsock_bind(), ast_netsock_find(), ast_netsock_sockfd(), ast_netsock_unref(), ast_strdupa, check_srcaddr(), defaultsockfd, IAX_DEFAULT_PORTNO, LOG_WARNING, iax2_peer::name, qos, socket_read(), iax2_peer::sockfd, iax2_trunk_peer::sockfd, and strsep().

Referenced by build_peer().

{
   struct sockaddr_in sin;
   int nonlocal = 1;
   int port = IAX_DEFAULT_PORTNO;
   int sockfd = defaultsockfd;
   char *tmp;
   char *addr;
   char *portstr;

   if (!(tmp = ast_strdupa(srcaddr)))
      return -1;

   addr = strsep(&tmp, ":");
   portstr = tmp;

   if (portstr) {
      port = atoi(portstr);
      if (port < 1)
         port = IAX_DEFAULT_PORTNO;
   }
   
   if (!ast_get_ip(&sin, addr)) {
      struct ast_netsock *sock;
      int res;

      sin.sin_port = 0;
      sin.sin_family = AF_INET;
      res = check_srcaddr((struct sockaddr *) &sin, sizeof(sin));
      if (res == 0) {
         /* ip address valid. */
         sin.sin_port = htons(port);
         if (!(sock = ast_netsock_find(netsock, &sin)))
            sock = ast_netsock_find(outsock, &sin);
         if (sock) {
            sockfd = ast_netsock_sockfd(sock);
            nonlocal = 0;
         } else {
            unsigned int orig_saddr = sin.sin_addr.s_addr;
            /* INADDR_ANY matches anyway! */
            sin.sin_addr.s_addr = INADDR_ANY;
            if (ast_netsock_find(netsock, &sin)) {
               sin.sin_addr.s_addr = orig_saddr;
               sock = ast_netsock_bind(outsock, io, srcaddr, port, qos.tos, qos.cos, socket_read, NULL);
               if (sock) {
                  sockfd = ast_netsock_sockfd(sock);
                  ast_netsock_unref(sock);
                  nonlocal = 0;
               } else {
                  nonlocal = 2;
               }
            }
         }
      }
   }
      
   peer->sockfd = sockfd;

   if (nonlocal == 1) {
      ast_log(LOG_WARNING, "Non-local or unbound address specified (%s) in sourceaddress for '%s', reverting to default\n",
         srcaddr, peer->name);
      return -1;
        } else if (nonlocal == 2) {
      ast_log(LOG_WARNING, "Unable to bind to sourceaddress '%s' for '%s', reverting to default\n",
         srcaddr, peer->name);
         return -1;
   } else {
      ast_debug(1, "Using sourceaddress %s for '%s'\n", srcaddr, peer->name);
      return 0;
   }
}
static int peer_status ( struct iax2_peer peer,
char *  status,
int  statuslen 
) [static]

peer_status: Report Peer status in character string

Definition at line 3567 of file chan_iax2.c.

References ast_copy_string(), iax2_peer::lastms, and iax2_peer::maxms.

Referenced by __iax2_show_peers(), function_iaxpeer(), handle_cli_iax2_show_peer(), and manager_iax2_show_peer_list().

{
   int res = 0;
   if (peer->maxms) {
      if (peer->lastms < 0) {
         ast_copy_string(status, "UNREACHABLE", statuslen);
      } else if (peer->lastms > peer->maxms) {
         snprintf(status, statuslen, "LAGGED (%d ms)", peer->lastms);
         res = 1;
      } else if (peer->lastms) {
         snprintf(status, statuslen, "OK (%d ms)", peer->lastms);
         res = 1;
      } else {
         ast_copy_string(status, "UNKNOWN", statuslen);
      }
   } else { 
      ast_copy_string(status, "Unmonitored", statuslen);
      res = -1;
   }
   return res;
}
static int peercnt_add ( struct sockaddr_in *  sin) [static]

Definition at line 2206 of file chan_iax2.c.

References peercnt::addr, iax2_trunk_peer::addr, ao2_alloc, ao2_find, ao2_link, ao2_lock(), ao2_ref, ao2_unlock(), ast_debug, ast_inet_ntoa(), ast_log(), peercnt::cur, peercnt::limit, LOG_ERROR, OBJ_POINTER, and set_peercnt_limit().

Referenced by __find_callno(), and complete_transfer().

{
   struct peercnt *peercnt;
   unsigned long addr = sin->sin_addr.s_addr;
   int res = 0;
   struct peercnt tmp = {
      .addr = addr,
   };

   /* Reasoning for peercnts container lock:  Two identical ip addresses
    * could be added by different threads at the "same time". Without the container
    * lock, both threads could alloc space for the same object and attempt
    * to link to table.  With the lock, one would create the object and link
    * to table while the other would find the already created peercnt object
    * rather than creating a new one. */
   ao2_lock(peercnts);
   if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
      ao2_lock(peercnt);
   } else if ((peercnt = ao2_alloc(sizeof(*peercnt), NULL))) {
      ao2_lock(peercnt);
      /* create and set defaults */
      peercnt->addr = addr;
      set_peercnt_limit(peercnt);
      /* guarantees it does not go away after unlocking table
       * ao2_find automatically adds this */
      ao2_link(peercnts, peercnt);
   } else {
      ao2_unlock(peercnts);
      return -1;
   }

   /* check to see if the address has hit its callno limit.  If not increment cur. */
   if (peercnt->limit > peercnt->cur) {
      peercnt->cur++;
      ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin->sin_addr));
   } else { /* max num call numbers for this peer has been reached! */
      ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_inet_ntoa(sin->sin_addr));
      res = -1;
   }

   /* clean up locks and ref count */
   ao2_unlock(peercnt);
   ao2_unlock(peercnts);
   ao2_ref(peercnt, -1); /* decrement ref from find/alloc, only the container ref remains. */

   return res;
}
static int peercnt_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2046 of file chan_iax2.c.

References peercnt::addr, CMP_MATCH, and CMP_STOP.

Referenced by load_objects().

{
   struct peercnt *peercnt1 = obj, *peercnt2 = arg;
   return (peercnt1->addr == peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
}
static int peercnt_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 2040 of file chan_iax2.c.

References peercnt::addr.

Referenced by load_objects().

{
   const struct peercnt *peercnt = obj;
   return abs((int) peercnt->addr);
}
static void peercnt_modify ( unsigned char  reg,
uint16_t  limit,
struct sockaddr_in *  sin 
) [static]

Definition at line 2178 of file chan_iax2.c.

References peercnt::addr, ao2_find, ao2_ref, ast_debug, ast_inet_ntoa(), peercnt::limit, OBJ_POINTER, peercnt::reg, and set_peercnt_limit().

Referenced by __expire_registry(), build_peer(), and update_registry().

{
   /* this function turns off and on custom callno limits set by peer registration */
   struct peercnt *peercnt;
   struct peercnt tmp = {
      .addr = sin->sin_addr.s_addr,
   };

   if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
      peercnt->reg = reg;
      if (limit) {
         peercnt->limit = limit;
      } else {
         set_peercnt_limit(peercnt);
      }
      ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_inet_ntoa(sin->sin_addr), peercnt->limit, peercnt->reg);
      ao2_ref(peercnt, -1); /* decrement ref from find */
   }
}
static void peercnt_remove ( struct peercnt peercnt) [static]

Definition at line 2258 of file chan_iax2.c.

References peercnt::addr, ao2_lock(), ao2_unlink, ao2_unlock(), ast_debug, ast_inet_ntoa(), and peercnt::cur.

Referenced by peercnt_remove_by_addr(), and peercnt_remove_cb().

{
   struct sockaddr_in sin = {
      .sin_addr.s_addr = peercnt->addr,
   };

   if (peercnt) {
      /* Container locked here since peercnt may be unlinked from list.  If left unlocked,
       * peercnt_add could try and grab this entry from the table and modify it at the
       * "same time" this thread attemps to unlink it.*/
      ao2_lock(peercnts);
      peercnt->cur--;
      ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr));
      /* if this was the last connection from the peer remove it from table */
      if (peercnt->cur == 0) {
         ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */
      }
      ao2_unlock(peercnts);
   }
}
static int peercnt_remove_by_addr ( struct sockaddr_in *  sin) [static]

Definition at line 2297 of file chan_iax2.c.

References peercnt::addr, ao2_find, ao2_ref, OBJ_POINTER, and peercnt_remove().

Referenced by __find_callno(), and complete_transfer().

{
   struct peercnt *peercnt;
   struct peercnt tmp = {
      .addr = sin->sin_addr.s_addr,
   };

   if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
      peercnt_remove(peercnt);
      ao2_ref(peercnt, -1); /* decrement ref from find */
   }
   return 0;
}
static int peercnt_remove_cb ( const void *  obj) [static]

Definition at line 2283 of file chan_iax2.c.

References ao2_ref, and peercnt_remove().

Referenced by sched_delay_remove().

{
   struct peercnt *peercnt = (struct peercnt *) obj;

   peercnt_remove(peercnt);
   ao2_ref(peercnt, -1); /* decrement ref from scheduler */

   return 0;
}
static void poke_all_peers ( void  ) [static]

Definition at line 12988 of file chan_iax2.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, iax2_poke_peer(), and peer_unref().

Referenced by reload_config().

{
   struct ao2_iterator i;
   struct iax2_peer *peer;

   i = ao2_iterator_init(peers, 0);
   while ((peer = ao2_iterator_next(&i))) {
      iax2_poke_peer(peer, 0);
      peer_unref(peer);
   }
   ao2_iterator_destroy(&i);
}
static int prune_addr_range_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2167 of file chan_iax2.c.

References CMP_MATCH, and addr_range::delme.

Referenced by reload_config().

{
   struct addr_range *addr_range = obj;

   return addr_range->delme ? CMP_MATCH : 0;
}
static void prune_peers ( void  ) [static]
static void prune_users ( void  ) [static]
static int pvt_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 13772 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, chan_iax2_pvt::frames_received, and match().

Referenced by load_objects().

{
   struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;

   /* The frames_received field is used to hold whether we're matching
    * against a full frame or not ... */

   return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt, 
      pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
}
static void pvt_destructor ( void *  obj) [static]

Definition at line 1752 of file chan_iax2.c.

References chan_iax2_pvt::addr, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_string_field_free_memory, ast_variables_destroy(), iax2_registry::callno, iax_frame::callno, chan_iax2_pvt::callno, chan_iax2_pvt::callno_entry, jb_frame::data, free_signaling_queue_entry(), iax2_destroy_helper(), iax2_frame_free(), IAX_ALREADYGONE, chan_iax2_pvt::jb, jb_destroy(), jb_getall(), JB_OK, chan_iax2_pvt::owner, chan_iax2_pvt::reg, iax_frame::retries, s, sched_delay_remove(), chan_iax2_pvt::signaling_queue, and chan_iax2_pvt::vars.

Referenced by new_iax().

{
   struct chan_iax2_pvt *pvt = obj;
   struct iax_frame *cur = NULL;
   struct signaling_queue_entry *s = NULL;

   ast_mutex_lock(&iaxsl[pvt->callno]);
   iax2_destroy_helper(pvt);
   sched_delay_remove(&pvt->addr, pvt->callno_entry);
   pvt->callno_entry = NULL;
   ast_mutex_unlock(&iaxsl[pvt->callno]);

   /* Already gone */
   ast_set_flag(pvt, IAX_ALREADYGONE); 

   AST_LIST_LOCK(&frame_queue);
   AST_LIST_TRAVERSE(&frame_queue, cur, list) {
      /* Cancel any pending transmissions */
      if (cur->callno == pvt->callno) { 
         cur->retries = -1;
      }
   }
   AST_LIST_UNLOCK(&frame_queue);

   while ((s = AST_LIST_REMOVE_HEAD(&pvt->signaling_queue, next))) {
      free_signaling_queue_entry(s);
   }

   if (pvt->reg) {
      pvt->reg->callno = 0;
   }

   if (!pvt->owner) {
      jb_frame frame;
      if (pvt->vars) {
          ast_variables_destroy(pvt->vars);
          pvt->vars = NULL;
      }

      while (jb_getall(pvt->jb, &frame) == JB_OK) {
         iax2_frame_free(frame.data);
      }

      jb_destroy(pvt->jb);
      ast_string_field_free_memory(pvt);
   }
}
static int pvt_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 13765 of file chan_iax2.c.

References chan_iax2_pvt::peercallno.

Referenced by load_objects().

{
   const struct chan_iax2_pvt *pvt = obj;

   return pvt->peercallno;
}
static int queue_signalling ( struct chan_iax2_pvt pvt,
struct ast_frame f 
) [static]

All frames other than that of type AST_FRAME_IAX must be held until we have received a destination call number.

Definition at line 1728 of file chan_iax2.c.

References ast_calloc, AST_FRAME_IAX, AST_LIST_INSERT_TAIL, ast_frame::data, ast_frame::frametype, free_signaling_queue_entry(), chan_iax2_pvt::hold_signaling, ast_frame::ptr, and chan_iax2_pvt::signaling_queue.

Referenced by __send_command().

{
   struct signaling_queue_entry *new;

   if (f->frametype == AST_FRAME_IAX || !pvt->hold_signaling) {
      return 1; /* do not queue this frame */
   } else if (!(new = ast_calloc(1, sizeof(struct signaling_queue_entry)))) {
      return -1;  /* out of memory */
   }

   memcpy(&new->f, f, sizeof(new->f)); /* copy ast_frame into our queue entry */

   if (new->f.datalen) { /* if there is data in this frame copy it over as well */
      if (!(new->f.data.ptr = ast_calloc(1, new->f.datalen))) {
         free_signaling_queue_entry(new);
         return -1;
      }
      memcpy(new->f.data.ptr, f->data.ptr, sizeof(*new->f.data.ptr));
   }
   AST_LIST_INSERT_TAIL(&pvt->signaling_queue, new, next);

   return 0;
}
static int raw_hangup ( struct sockaddr_in *  sin,
unsigned short  src,
unsigned short  dst,
int  sockfd 
) [static]

Definition at line 7456 of file chan_iax2.c.

References ast_debug, AST_FRAME_IAX, ast_inet_ntoa(), compress_subclass(), ast_iax2_full_hdr::csub, ast_iax2_full_hdr::dcallno, IAX_COMMAND_INVAL, IAX_FLAG_FULL, iax_outputframe(), ast_iax2_full_hdr::iseqno, option_debug, ast_iax2_full_hdr::oseqno, ast_iax2_full_hdr::scallno, ast_iax2_full_hdr::ts, and ast_iax2_full_hdr::type.

Referenced by socket_process().

{
   struct ast_iax2_full_hdr fh;
   fh.scallno = htons(src | IAX_FLAG_FULL);
   fh.dcallno = htons(dst);
   fh.ts = 0;
   fh.oseqno = 0;
   fh.iseqno = 0;
   fh.type = AST_FRAME_IAX;
   fh.csub = compress_subclass(IAX_COMMAND_INVAL);
   iax_outputframe(NULL, &fh, 0, sin, 0);
#if 0
   if (option_debug)
#endif   
      ast_debug(1, "Raw Hangup %s:%d, src=%d, dst=%d\n",
         ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), src, dst);
   return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
}
static struct iax2_peer * realtime_peer ( const char *  peername,
struct sockaddr_in *  sin 
) [static, read]
Note:
This function calls reg_source_db -> iax2_poke_peer -> find_callno, so do not call this with a pvt lock held.

Note:
If this one loaded something, then we need to ensure that the host field matched. The only reason why we can't have this as a criteria is because we only have the IP address and the host field might be set as a name (and the reverse PTR might not match).

Definition at line 4148 of file chan_iax2.c.

References iax2_peer::addr, ao2_link, ast_copy_flags, ast_debug, ast_get_time_t(), ast_gethostbyname(), ast_inet_ntoa(), ast_load_realtime(), ast_sched_thread_del, ast_set_flag, ast_test_flag, ast_variables_destroy(), build_peer(), iax2_peer::expire, expire_registry(), hp, iax2_sched_add(), IAX_DEFAULT_REG_EXPIRE, IAX_DYNAMIC, IAX_RTAUTOCLEAR, IAX_RTCACHEFRIENDS, IAX_RTIGNOREREGEXPIRE, IAX_TEMPONLY, inet_aton(), iax2_peer::name, ast_variable::name, ast_variable::next, peer_ref(), peer_unref(), realtime_update_peer(), reg_source_db(), SENTINEL, ast_variable::value, and var.

Referenced by authenticate_reply(), calltoken_required(), find_peer(), and iax2_getpeername().

{
   struct ast_variable *var = NULL;
   struct ast_variable *tmp;
   struct iax2_peer *peer=NULL;
   time_t regseconds = 0, nowtime;
   int dynamic=0;

   if (peername) {
      var = ast_load_realtime("iaxpeers", "name", peername, "host", "dynamic", SENTINEL);
      if (!var && sin)
         var = ast_load_realtime("iaxpeers", "name", peername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
   } else if (sin) {
      char porta[25];
      sprintf(porta, "%d", ntohs(sin->sin_port));
      var = ast_load_realtime("iaxpeers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
      if (var) {
         /* We'll need the peer name in order to build the structure! */
         for (tmp = var; tmp; tmp = tmp->next) {
            if (!strcasecmp(tmp->name, "name"))
               peername = tmp->value;
         }
      }
   }
   if (!var && peername) { /* Last ditch effort */
      var = ast_load_realtime("iaxpeers", "name", peername, SENTINEL);
      /*!\note
       * If this one loaded something, then we need to ensure that the host
       * field matched.  The only reason why we can't have this as a criteria
       * is because we only have the IP address and the host field might be
       * set as a name (and the reverse PTR might not match).
       */
      if (var && sin) {
         for (tmp = var; tmp; tmp = tmp->next) {
            if (!strcasecmp(tmp->name, "host")) {
               struct ast_hostent ahp;
               struct hostent *hp;
               if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {
                  /* No match */
                  ast_variables_destroy(var);
                  var = NULL;
               }
               break;
            }
         }
      }
   }
   if (!var)
      return NULL;

   peer = build_peer(peername, var, NULL, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
   
   if (!peer) {
      ast_variables_destroy(var);
      return NULL;
   }

   for (tmp = var; tmp; tmp = tmp->next) {
      /* Make sure it's not a user only... */
      if (!strcasecmp(tmp->name, "type")) {
         if (strcasecmp(tmp->value, "friend") &&
             strcasecmp(tmp->value, "peer")) {
            /* Whoops, we weren't supposed to exist! */
            peer = peer_unref(peer);
            break;
         } 
      } else if (!strcasecmp(tmp->name, "regseconds")) {
         ast_get_time_t(tmp->value, &regseconds, 0, NULL);
      } else if (!strcasecmp(tmp->name, "ipaddr")) {
         inet_aton(tmp->value, &(peer->addr.sin_addr));
      } else if (!strcasecmp(tmp->name, "port")) {
         peer->addr.sin_port = htons(atoi(tmp->value));
      } else if (!strcasecmp(tmp->name, "host")) {
         if (!strcasecmp(tmp->value, "dynamic"))
            dynamic = 1;
      }
   }

   ast_variables_destroy(var);

   if (!peer)
      return NULL;

   if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
      ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
      if (ast_test_flag(peer, IAX_RTAUTOCLEAR)) {
         if (peer->expire > -1) {
            if (!ast_sched_thread_del(sched, peer->expire)) {
               peer->expire = -1;
               peer_unref(peer);
            }
         }
         peer->expire = iax2_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer_ref(peer));
         if (peer->expire == -1)
            peer_unref(peer);
      }
      ao2_link(peers, peer);
      if (ast_test_flag(peer, IAX_DYNAMIC))
         reg_source_db(peer);
   } else {
      ast_set_flag(peer, IAX_TEMPONLY);   
   }

   if (!ast_test_flag(&globalflags, IAX_RTIGNOREREGEXPIRE) && dynamic) {
      time(&nowtime);
      if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
         memset(&peer->addr, 0, sizeof(peer->addr));
         realtime_update_peer(peer->name, &peer->addr, 0);
         ast_debug(1, "realtime_peer: Bah, '%s' is expired (%d/%d/%d)!\n",
            peername, (int)(nowtime - regseconds), (int)regseconds, (int)nowtime);
      }
      else {
         ast_debug(1, "realtime_peer: Registration for '%s' still active (%d/%d/%d)!\n",
            peername, (int)(nowtime - regseconds), (int)regseconds, (int)nowtime);
      }
   }

   return peer;
}
static void realtime_update_peer ( const char *  peername,
struct sockaddr_in *  sin,
time_t  regtime 
) [static]

Definition at line 4339 of file chan_iax2.c.

References ast_inet_ntoa(), ast_update_realtime(), and SENTINEL.

Referenced by __expire_registry(), realtime_peer(), and update_registry().

{
   char port[10];
   char regseconds[20];
   
   snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
   snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
   ast_update_realtime("iaxpeers", "name", peername, 
      "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", port, 
      "regseconds", regseconds, SENTINEL);
}
static struct iax2_user * realtime_user ( const char *  username,
struct sockaddr_in *  sin 
) [static, read]

Note:
If this one loaded something, then we need to ensure that the host field matched. The only reason why we can't have this as a criteria is because we only have the IP address and the host field might be set as a name (and the reverse PTR might not match).

Definition at line 4268 of file chan_iax2.c.

References ao2_link, ast_gethostbyname(), ast_inet_ntoa(), ast_load_realtime(), ast_set_flag, ast_test_flag, ast_variables_destroy(), build_user(), hp, IAX_RTCACHEFRIENDS, IAX_TEMPONLY, ast_variable::name, ast_variable::next, SENTINEL, user, ast_variable::value, and var.

Referenced by calltoken_required(), and check_access().

{
   struct ast_variable *var;
   struct ast_variable *tmp;
   struct iax2_user *user=NULL;

   var = ast_load_realtime("iaxusers", "name", username, "host", "dynamic", SENTINEL);
   if (!var)
      var = ast_load_realtime("iaxusers", "name", username, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
   if (!var && sin) {
      char porta[6];
      snprintf(porta, sizeof(porta), "%d", ntohs(sin->sin_port));
      var = ast_load_realtime("iaxusers", "name", username, "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
      if (!var)
         var = ast_load_realtime("iaxusers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
   }
   if (!var) { /* Last ditch effort */
      var = ast_load_realtime("iaxusers", "name", username, SENTINEL);
      /*!\note
       * If this one loaded something, then we need to ensure that the host
       * field matched.  The only reason why we can't have this as a criteria
       * is because we only have the IP address and the host field might be
       * set as a name (and the reverse PTR might not match).
       */
      if (var) {
         for (tmp = var; tmp; tmp = tmp->next) {
            if (!strcasecmp(tmp->name, "host")) {
               struct ast_hostent ahp;
               struct hostent *hp;
               if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) {
                  /* No match */
                  ast_variables_destroy(var);
                  var = NULL;
               }
               break;
            }
         }
      }
   }
   if (!var)
      return NULL;

   tmp = var;
   while(tmp) {
      /* Make sure it's not a peer only... */
      if (!strcasecmp(tmp->name, "type")) {
         if (strcasecmp(tmp->value, "friend") &&
             strcasecmp(tmp->value, "user")) {
            return NULL;
         } 
      }
      tmp = tmp->next;
   }

   user = build_user(username, var, NULL, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));

   ast_variables_destroy(var);

   if (!user)
      return NULL;

   if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
      ast_set_flag(user, IAX_RTCACHEFRIENDS);
      ao2_link(users, user);
   } else {
      ast_set_flag(user, IAX_TEMPONLY);   
   }

   return user;
}
static void reg_source_db ( struct iax2_peer p) [static]

Definition at line 8331 of file chan_iax2.c.

References iax2_peer::addr, ast_db_get(), AST_DEVICE_UNKNOWN, ast_devstate_changed(), ast_inet_ntoa(), ast_sched_thread_del, ast_test_flag, ast_verb, iax2_peer::expire, expire_registry(), iax2_peer::expiry, iax2_poke_peer(), iax2_regfunk, iax2_sched_add(), IAX_TEMPONLY, inet_aton(), iax2_peer::name, peer_ref(), peer_unref(), and register_peer_exten().

Referenced by realtime_peer(), and set_config().

{
   char data[80];
   struct in_addr in;
   char *c, *d;
   if (!ast_test_flag(p, IAX_TEMPONLY) && (!ast_db_get("IAX/Registry", p->name, data, sizeof(data)))) {
      c = strchr(data, ':');
      if (c) {
         *c = '\0';
         c++;
         if (inet_aton(data, &in)) {
            d = strchr(c, ':');
            if (d) {
               *d = '\0';
               d++;
               ast_verb(3, "Seeding '%s' at %s:%d for %d\n", p->name,
                  ast_inet_ntoa(in), atoi(c), atoi(d));
               iax2_poke_peer(p, 0);
               p->expiry = atoi(d);
               memset(&p->addr, 0, sizeof(p->addr));
               p->addr.sin_family = AF_INET;
               p->addr.sin_addr = in;
               p->addr.sin_port = htons(atoi(c));
               if (p->expire > -1) {
                  if (!ast_sched_thread_del(sched, p->expire)) {
                     p->expire = -1;
                     peer_unref(p);
                  }
               }
               ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
               p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
               if (p->expire == -1)
                  peer_unref(p);
               if (iax2_regfunk)
                  iax2_regfunk(p->name, 1);
               register_peer_exten(p, 1);
            }              
               
         }
      }
   }
}
static void register_peer_exten ( struct iax2_peer peer,
int  onoff 
) [static]

Definition at line 8250 of file chan_iax2.c.

References ast_add_extension(), ast_context_remove_extension(), ast_copy_string(), ast_exists_extension(), ast_free_ptr, ast_strdup, ast_strlen_zero(), ext, iax2_peer::name, iax2_peer::regexten, S_OR, and strsep().

Referenced by __expire_registry(), peer_destructor(), reg_source_db(), and update_registry().

{
   char multi[256];
   char *stringp, *ext;
   if (!ast_strlen_zero(regcontext)) {
      ast_copy_string(multi, S_OR(peer->regexten, peer->name), sizeof(multi));
      stringp = multi;
      while((ext = strsep(&stringp, "&"))) {
         if (onoff) {
            if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL))
               ast_add_extension(regcontext, 1, ext, 1, NULL, NULL,
                       "Noop", ast_strdup(peer->name), ast_free_ptr, "IAX2");
         } else
            ast_context_remove_extension(regcontext, ext, 1, NULL);
      }
   }
}
static int register_verify ( int  callno,
struct sockaddr_in *  sin,
struct iax_ies ies 
) [static]

Verify inbound registration.

Definition at line 7630 of file chan_iax2.c.

References ast_apply_ha(), ast_check_signature, ast_clear_flag, ast_copy_string(), AST_DEVICE_UNKNOWN, ast_devstate_changed(), ast_inet_ntoa(), ast_key_get, AST_KEY_PUBLIC, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, iax2_peer::authmethods, chan_iax2_pvt::expiry, find_peer(), iax2_peer::ha, IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_AUTH_RSA, IAX_DYNAMIC, IAX_STATE_AUTHENTICATED, iax2_peer::inkeys, LOG_NOTICE, LOG_WARNING, iax_ies::md5_result, MD5Final(), MD5Init(), MD5Update(), iax2_peer::name, iax_ies::password, peer_unref(), iax_ies::refresh, iax_ies::rsa_result, iax2_peer::secret, secret, strsep(), and iax_ies::username.

Referenced by socket_process().

{
   char requeststr[256] = "";
   char peer[256] = "";
   char md5secret[256] = "";
   char rsasecret[256] = "";
   char secret[256] = "";
   struct iax2_peer *p = NULL;
   struct ast_key *key;
   char *keyn;
   int x;
   int expire = 0;
   int res = -1;

   ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
   /* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
   if (ies->username)
      ast_copy_string(peer, ies->username, sizeof(peer));
   if (ies->password)
      ast_copy_string(secret, ies->password, sizeof(secret));
   if (ies->md5_result)
      ast_copy_string(md5secret, ies->md5_result, sizeof(md5secret));
   if (ies->rsa_result)
      ast_copy_string(rsasecret, ies->rsa_result, sizeof(rsasecret));
   if (ies->refresh)
      expire = ies->refresh;

   if (ast_strlen_zero(peer)) {
      ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(sin->sin_addr));
      return -1;
   }

   /* SLD: first call to lookup peer during registration */
   ast_mutex_unlock(&iaxsl[callno]);
   p = find_peer(peer, 1);
   ast_mutex_lock(&iaxsl[callno]);
   if (!p || !iaxs[callno]) {
      if (iaxs[callno]) {
         int plaintext = ((last_authmethod & IAX_AUTH_PLAINTEXT) | (iaxs[callno]->authmethods & IAX_AUTH_PLAINTEXT));
         /* Anything, as long as it's non-blank */
         ast_string_field_set(iaxs[callno], secret, "badsecret");
         /* An AUTHREQ must be sent in response to a REGREQ of an invalid peer unless
          * 1. A challenge already exists indicating a AUTHREQ was already sent out.
          * 2. A plaintext secret is present in ie as result of a previous AUTHREQ requesting it.
          * 3. A plaintext secret is present in the ie and the last_authmethod used by a peer happened
          *    to be plaintext, indicating it is an authmethod used by other peers on the system. 
          *
          * If none of these cases exist, res will be returned as 0 without authentication indicating
          * an AUTHREQ needs to be sent out. */

         if (ast_strlen_zero(iaxs[callno]->challenge) &&
            !(!ast_strlen_zero(secret) && plaintext)) {
            /* by setting res to 0, an REGAUTH will be sent */
            res = 0;
         }
      }
      if (authdebug && !p)
         ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
      goto return_unref;
   }

   if (!ast_test_flag(p, IAX_DYNAMIC)) {
      if (authdebug)
         ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
      goto return_unref;
   }

   if (!ast_apply_ha(p->ha, sin)) {
      if (authdebug)
         ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
      goto return_unref;
   }
   ast_string_field_set(iaxs[callno], secret, p->secret);
   ast_string_field_set(iaxs[callno], inkeys, p->inkeys);
   /* Check secret against what we have on file */
   if (!ast_strlen_zero(rsasecret) && (p->authmethods & IAX_AUTH_RSA) && !ast_strlen_zero(iaxs[callno]->challenge)) {
      if (!ast_strlen_zero(p->inkeys)) {
         char tmpkeys[256];
         char *stringp=NULL;
         ast_copy_string(tmpkeys, p->inkeys, sizeof(tmpkeys));
         stringp=tmpkeys;
         keyn = strsep(&stringp, ":");
         while(keyn) {
            key = ast_key_get(keyn, AST_KEY_PUBLIC);
            if (key && !ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) {
               ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
               break;
            } else if (!key)
               ast_log(LOG_WARNING, "requested inkey '%s' does not exist\n", keyn);
            keyn = strsep(&stringp, ":");
         }
         if (!keyn) {
            if (authdebug)
               ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
            goto return_unref;
         }
      } else {
         if (authdebug)
            ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
         goto return_unref;
      }
   } else if (!ast_strlen_zero(md5secret) && (p->authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(iaxs[callno]->challenge)) {
      struct MD5Context md5;
      unsigned char digest[16];
      char *tmppw, *stringp;

      tmppw = ast_strdupa(p->secret);
      stringp = tmppw;
      while((tmppw = strsep(&stringp, ";"))) {
         MD5Init(&md5);
         MD5Update(&md5, (unsigned char *)iaxs[callno]->challenge, strlen(iaxs[callno]->challenge));
         MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
         MD5Final(digest, &md5);
         for (x=0;x<16;x++)
            sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
         if (!strcasecmp(requeststr, md5secret))
            break;
      }
      if (tmppw) {
         ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
      } else {
         if (authdebug)
            ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
         goto return_unref;
      }
   } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
      /* They've provided a plain text password and we support that */
      if (strcmp(secret, p->secret)) {
         if (authdebug)
            ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
         goto return_unref;
      } else
         ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
   } else if (!ast_strlen_zero(iaxs[callno]->challenge) && ast_strlen_zero(md5secret) && ast_strlen_zero(rsasecret)) {
      /* if challenge has been sent, but no challenge response if given, reject. */
      goto return_unref;
   }
   ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */

   /* either Authentication has taken place, or a REGAUTH must be sent before verifying registration */
   res = 0;

return_unref:
   if (iaxs[callno]) {
      ast_string_field_set(iaxs[callno], peer, peer);

      /* Choose lowest expiry number */
      if (expire && (expire < iaxs[callno]->expiry)) {
         iaxs[callno]->expiry = expire;
      }
   }

   if (p) {
      peer_unref(p);
   }
   return res;
}
static int registry_authrequest ( int  callno) [static]

Definition at line 8539 of file chan_iax2.c.

References AST_FRAME_IAX, ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_strdupa, ast_string_field_set, chan_iax2_pvt::authmethods, iax2_peer::authmethods, iax_ie_data::buf, iax2_peer::callno, find_peer(), IAX_AUTH_MD5, IAX_AUTH_PLAINTEXT, IAX_AUTH_RSA, IAX_COMMAND_REGAUTH, iax_ie_append_short(), iax_ie_append_str(), IAX_IE_AUTHMETHODS, IAX_IE_CHALLENGE, IAX_IE_USERNAME, peer_unref(), iax_ie_data::pos, and send_command().

Referenced by socket_process().

{
   struct iax_ie_data ied;
   struct iax2_peer *p;
   char challenge[10];
   const char *peer_name;
   int sentauthmethod;

   peer_name = ast_strdupa(iaxs[callno]->peer);

   /* SLD: third call to find_peer in registration */
   ast_mutex_unlock(&iaxsl[callno]);
   if ((p = find_peer(peer_name, 1))) {
      last_authmethod = p->authmethods;
   }

   ast_mutex_lock(&iaxsl[callno]);
   if (!iaxs[callno])
      goto return_unref;

   memset(&ied, 0, sizeof(ied));
   /* The selection of which delayed reject is sent may leak information,
    * if it sets a static response.  For example, if a host is known to only
    * use MD5 authentication, then an RSA response would indicate that the
    * peer does not exist, and vice-versa.
    * Therefore, we use whatever the last peer used (which may vary over the
    * course of a server, which should leak minimal information). */
   sentauthmethod = p ? p->authmethods : last_authmethod ? last_authmethod : (IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT);
   if (!p) {
      iaxs[callno]->authmethods = sentauthmethod;
   }
   iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, sentauthmethod);
   if (sentauthmethod & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
      /* Build the challenge */
      snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
      ast_string_field_set(iaxs[callno], challenge, challenge);
      iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
   }
   iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);

return_unref:
   if (p) {
      peer_unref(p);
   }

   return iaxs[callno] ? send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1) : -1;
}
static int registry_rerequest ( struct iax_ies ies,
int  callno,
struct sockaddr_in *  sin 
) [static]

Definition at line 8587 of file chan_iax2.c.

References add_empty_calltoken_ie(), iax2_registry::addr, ast_copy_string(), AST_FRAME_IAX, ast_inet_ntoa(), ast_log(), ast_strlen_zero(), authenticate(), iax_ies::authmethods, iax_ie_data::buf, iax_ies::challenge, IAX_COMMAND_REGREQ, iax_ie_append_short(), iax_ie_append_str(), IAX_IE_REFRESH, IAX_IE_USERNAME, inaddrcmp(), LOG_NOTICE, LOG_WARNING, iax_ie_data::pos, iax2_registry::refresh, chan_iax2_pvt::reg, REG_STATE_AUTHSENT, REG_STATE_NOAUTH, iax2_registry::regstate, iax2_registry::secret, send_command(), iax2_registry::username, and iax_ies::username.

Referenced by socket_process().

{
   struct iax2_registry *reg;
   /* Start pessimistic */
   struct iax_ie_data ied;
   char peer[256] = "";
   char challenge[256] = "";
   int res;
   int authmethods = 0;
   if (ies->authmethods)
      authmethods = ies->authmethods;
   if (ies->username)
      ast_copy_string(peer, ies->username, sizeof(peer));
   if (ies->challenge)
      ast_copy_string(challenge, ies->challenge, sizeof(challenge));
   memset(&ied, 0, sizeof(ied));
   reg = iaxs[callno]->reg;
   if (reg) {
         if (inaddrcmp(&reg->addr, sin)) {
            ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(sin->sin_addr));
            return -1;
         }
         if (ast_strlen_zero(reg->secret)) {
            ast_log(LOG_NOTICE, "No secret associated with peer '%s'\n", reg->username);
            reg->regstate = REG_STATE_NOAUTH;
            return -1;
         }
         iax_ie_append_str(&ied, IAX_IE_USERNAME, reg->username);
         iax_ie_append_short(&ied, IAX_IE_REFRESH, reg->refresh);
         if (reg->secret[0] == '[') {
            char tmpkey[256];
            ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
            tmpkey[strlen(tmpkey) - 1] = '\0';
            res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL);
         } else
            res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL);
         if (!res) {
            reg->regstate = REG_STATE_AUTHSENT;
            add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
            return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
         } else
            return -1;
         ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
   } else   
      ast_log(LOG_NOTICE, "Can't reregister without a reg\n");
   return -1;
}
static char* regstate2str ( int  regstate) [static]

Definition at line 6746 of file chan_iax2.c.

References REG_STATE_AUTHSENT, REG_STATE_NOAUTH, REG_STATE_REGISTERED, REG_STATE_REGSENT, REG_STATE_REJECTED, REG_STATE_TIMEOUT, and REG_STATE_UNREGISTERED.

Referenced by handle_cli_iax2_show_registry(), and manager_iax2_show_registry().

{
   switch(regstate) {
   case REG_STATE_UNREGISTERED:
      return "Unregistered";
   case REG_STATE_REGSENT:
      return "Request Sent";
   case REG_STATE_AUTHSENT:
      return "Auth. Sent";
   case REG_STATE_REGISTERED:
      return "Registered";
   case REG_STATE_REJECTED:
      return "Rejected";
   case REG_STATE_TIMEOUT:
      return "Timeout";
   case REG_STATE_NOAUTH:
      return "No Authentication";
   default:
      return "Unknown";
   }
}
static int reload ( void  ) [static]

Definition at line 13049 of file chan_iax2.c.

References reload_config().

{
   return reload_config();
}
static void reload_firmware ( int  unload) [static]

Definition at line 3064 of file chan_iax2.c.

References ast_config_AST_DATA_DIR, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_verb, iax_firmware::dead, destroy_firmware(), dir, errno, LOG_WARNING, and try_firmware().

Referenced by __unload_module(), load_module(), and reload_config().

{
   struct iax_firmware *cur = NULL;
   DIR *fwd;
   struct dirent *de;
   char dir[256], fn[256];

   AST_LIST_LOCK(&firmwares);

   /* Mark all as dead */
   AST_LIST_TRAVERSE(&firmwares, cur, list)
      cur->dead = 1;

   /* Now that we have marked them dead... load new ones */
   if (!unload) {
      snprintf(dir, sizeof(dir), "%s/firmware/iax", ast_config_AST_DATA_DIR);
      fwd = opendir(dir);
      if (fwd) {
         while((de = readdir(fwd))) {
            if (de->d_name[0] != '.') {
               snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);
               if (!try_firmware(fn)) {
                  ast_verb(2, "Loaded firmware '%s'\n", de->d_name);
               }
            }
         }
         closedir(fwd);
      } else 
         ast_log(LOG_WARNING, "Error opening firmware directory '%s': %s\n", dir, strerror(errno));
   }

   /* Clean up leftovers */
   AST_LIST_TRAVERSE_SAFE_BEGIN(&firmwares, cur, list) {
      if (!cur->dead)
         continue;
      AST_LIST_REMOVE_CURRENT(list);
      destroy_firmware(cur);
   }
   AST_LIST_TRAVERSE_SAFE_END;

   AST_LIST_UNLOCK(&firmwares);
}
static void remove_by_peercallno ( struct chan_iax2_pvt pvt) [static]

Definition at line 2009 of file chan_iax2.c.

References ao2_unlink, ast_log(), LOG_ERROR, and chan_iax2_pvt::peercallno.

Referenced by complete_transfer(), iax2_destroy(), resend_with_token(), and socket_process().

{
   if (!pvt->peercallno) {
      ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
      return;
   }

   ao2_unlink(iax_peercallno_pvts, pvt);
}
static void remove_by_transfercallno ( struct chan_iax2_pvt pvt) [static]

Definition at line 1990 of file chan_iax2.c.

References ao2_unlink, ast_log(), LOG_ERROR, and chan_iax2_pvt::transfercallno.

Referenced by complete_transfer(), and iax2_destroy().

{
   if (!pvt->transfercallno) {
      ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
      return;
   }

   ao2_unlink(iax_transfercallno_pvts, pvt);
}
static int replace_callno ( const void *  obj) [static]

Definition at line 2495 of file chan_iax2.c.

References ao2_link, ao2_lock(), ao2_ref, ao2_unlock(), ast_log(), callno_entry::callno, LOG_ERROR, TRUNK_CALL_START, and callno_entry::validated.

Referenced by __find_callno(), make_trunk(), and sched_delay_remove().

{
   struct callno_entry *callno_entry = (struct callno_entry *) obj;

   /* the callno_pool container is locked here primarily to ensure thread
    * safety of the total_nonval_callno_used check and decrement */
   ao2_lock(callno_pool);

   if (!callno_entry->validated && (total_nonval_callno_used != 0)) {
      total_nonval_callno_used--;
   } else if (!callno_entry->validated && (total_nonval_callno_used == 0)) {
      ast_log(LOG_ERROR, "Attempted to decrement total non calltoken validated callnumbers below zero... Callno is:%d \n", callno_entry->callno);
   }

   if (callno_entry->callno < TRUNK_CALL_START) {
      ao2_link(callno_pool, callno_entry);
   } else {
      ao2_link(callno_pool_trunk, callno_entry);
   }
   ao2_ref(callno_entry, -1); /* only container ref remains */

   ao2_unlock(callno_pool);
   return 0;
}
static void requirecalltoken_mark_auto ( const char *  name,
int  subclass 
) [static]

Definition at line 4627 of file chan_iax2.c.

References ast_strlen_zero(), CALLTOKEN_AUTO, iax2_peer::calltoken_required, iax2_user::calltoken_required, CALLTOKEN_YES, find_peer(), find_user(), IAX_COMMAND_NEW, peer_unref(), and user_unref().

Referenced by handle_call_token().

{
   struct iax2_user *user = NULL;
   struct iax2_peer *peer = NULL;

   if (ast_strlen_zero(name)) {
      return; /* no username given */
   }

   if ((subclass == IAX_COMMAND_NEW) && (user = find_user(name)) && (user->calltoken_required == CALLTOKEN_AUTO)) {
      user->calltoken_required = CALLTOKEN_YES;
   } else if ((subclass != IAX_COMMAND_NEW) && (peer = find_peer(name, 1)) && (peer->calltoken_required == CALLTOKEN_AUTO)) {
      peer->calltoken_required = CALLTOKEN_YES;
   }

   if (peer) {
      peer_unref(peer);
   }
   if (user) {
      user_unref(user);
   }
}
static void resend_with_token ( int  callno,
struct iax_frame f,
const char *  newtoken 
) [static]

Definition at line 4543 of file chan_iax2.c.

References iax_frame::af, chan_iax2_pvt::aseqno, AST_FRAME_IAX, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, iax_ie_data::buf, chan_iax2_pvt::callno, chan_iax2_pvt::calltoken_ie_len, iax_frame::data, iax_frame::datalen, iax_frame::dcallno, iax_frame::encmethods, ast_frame::frametype, iax2_allow_new(), iax2_frame_free(), iax_ie_append_str(), IAX_IE_CALLTOKEN, chan_iax2_pvt::iseqno, chan_iax2_pvt::oseqno, chan_iax2_pvt::peercallno, remove_by_peercallno(), chan_iax2_pvt::rseqno, send_command(), and ast_frame::subclass.

Referenced by socket_process().

{
   struct chan_iax2_pvt *pvt = iaxs[callno];
   int frametype = f->af.frametype;
   int subclass = f->af.subclass;
   struct {
      struct ast_iax2_full_hdr fh;
      struct iax_ie_data ied;
   } data = {
      .ied.buf = { 0 },
      .ied.pos = 0,
   };
   /* total len - header len gives us the frame's IE len */
   int ie_data_pos = f->datalen - sizeof(struct ast_iax2_full_hdr);

   if (!pvt) {
      return;  /* this should not be possible if called from socket_process() */
   }

   /* 
    * Check to make sure last frame sent is valid for call token resend
    * 1. Frame should _NOT_ be encrypted since it starts the IAX dialog 
    * 2. Frame should _NOT_ already have a destination callno
    * 3. Frame must be a valid iax_frame subclass capable of starting dialog
    * 4. Pvt must have a calltoken_ie_len which represents the number of
    *    bytes at the end of the frame used for the previous calltoken ie.
    * 5. Pvt's calltoken_ie_len must be _LESS_ than the total IE length
    * 6. Total length of f->data must be _LESS_ than size of our data struct
    *    because f->data must be able to fit within data. 
    */
   if (f->encmethods || f->dcallno || !iax2_allow_new(frametype, subclass, 0)
      || !pvt->calltoken_ie_len || (pvt->calltoken_ie_len > ie_data_pos) ||
      (f->datalen > sizeof(data))) {

      return;  /* ignore resend, token was not valid for the dialog */
   }

   /* token is valid
    * 1. Copy frame data over
    * 2. Redo calltoken IE, it will always be the last ie in the frame.
    *    NOTE: Having the ie always be last is not protocol specified,
    *    it is only an implementation choice.  Since we only expect the ie to
    *    be last for frames we have sent, this can no way be affected by
    *    another end point.
    * 3. Remove frame from queue
    * 4. Free old frame
    * 5. Clear previous seqnos
    * 6. Resend with CALLTOKEN ie.
    */

   /* ---1.--- */
   memcpy(&data, f->data, f->datalen);
   data.ied.pos = ie_data_pos;

   /* ---2.--- */
   /* move to the beginning of the calltoken ie so we can write over it */
   data.ied.pos -= pvt->calltoken_ie_len;
   iax_ie_append_str(&data.ied, IAX_IE_CALLTOKEN, newtoken);

   /* make sure to update token length incase it ever has to be stripped off again */
   pvt->calltoken_ie_len = data.ied.pos - ie_data_pos; /* new pos minus old pos tells how big token ie is */

   /* ---3.--- */
   AST_LIST_LOCK(&frame_queue);
   AST_LIST_REMOVE(&frame_queue, f, list);
   AST_LIST_UNLOCK(&frame_queue);

   /* ---4.--- */
   iax2_frame_free(f);

   /* ---5.--- */
   pvt->oseqno = 0;
   pvt->rseqno = 0;
   pvt->iseqno = 0;
   pvt->aseqno = 0;
   if (pvt->peercallno) {
      remove_by_peercallno(pvt);
      pvt->peercallno = 0;
   }

   /* ---6.--- */
   send_command(pvt, AST_FRAME_IAX, subclass, 0, data.ied.buf, data.ied.pos, -1);
}
static void save_osptoken ( struct iax_frame fr,
struct iax_ies ies 
) [static]

Definition at line 9068 of file chan_iax2.c.

References ast_string_field_set, iax_frame::callno, IAX_MAX_OSPBLOCK_NUM, IAX_MAX_OSPBLOCK_SIZE, IAX_MAX_OSPBUFF_SIZE, iax_ies::ospblocklength, and iax_ies::osptokenblock.

Referenced by socket_process().

{
   int i;
   unsigned int length, offset = 0;
   char full_osptoken[IAX_MAX_OSPBUFF_SIZE];

   for (i = 0; i < IAX_MAX_OSPBLOCK_NUM; i++) {
      length = ies->ospblocklength[i];
      if (length != 0) {
         if (length > IAX_MAX_OSPBLOCK_SIZE) {
            /* OSP token block length wrong, clear buffer */
            offset = 0;
            break;
         } else {
            memcpy(full_osptoken + offset, ies->osptokenblock[i], length);
            offset += length;
         }
      } else {
         break;
      }
   }
   *(full_osptoken + offset) = '\0';
   if (strlen(full_osptoken) != offset) {
      /* OSP token length wrong, clear buffer */
      *full_osptoken = '\0';
   }

   ast_string_field_set(iaxs[fr->callno], osptoken, full_osptoken);
}
static void sched_delay_remove ( struct sockaddr_in *  sin,
struct callno_entry callno_entry 
) [static]

Definition at line 2567 of file chan_iax2.c.

References peercnt::addr, ao2_find, ao2_ref, ast_debug, ast_inet_ntoa(), iax2_sched_add(), MIN_REUSE_TIME, OBJ_POINTER, peercnt_remove_cb(), and replace_callno().

Referenced by pvt_destructor().

{
   int i;
   struct peercnt *peercnt;
   struct peercnt tmp = {
      .addr = sin->sin_addr.s_addr,
   };

   if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
      /* refcount is incremented with ao2_find.  keep that ref for the scheduler */
      ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_inet_ntoa(sin->sin_addr), MIN_REUSE_TIME);
      i = iax2_sched_add(sched, MIN_REUSE_TIME * 1000, peercnt_remove_cb, peercnt);
      if (i == -1) {
         ao2_ref(peercnt, -1);
      }
   }

   iax2_sched_add(sched, MIN_REUSE_TIME * 1000, replace_callno, callno_entry);
}
static int schedule_delivery ( struct iax_frame fr,
int  updatehistory,
int  fromtrunk,
unsigned int *  tsout 
) [static]
Note:
This function assumes fr->callno is locked
IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno] was valid before calling it, it may no longer be valid after calling it.

Definition at line 3992 of file chan_iax2.c.

References __do_deliver(), iax_frame::af, ast_bridged_channel(), AST_CHAN_TP_WANTSJITTER, ast_channel_unlock, ast_codec_get_samples(), ast_debug, ast_format_rate(), AST_FRAME_CNG, AST_FRAME_VOICE, ast_samp2tv(), ast_sched_thread_del, ast_test_flag, ast_tv(), ast_tvadd(), ast_tvzero(), ast_channel::bridge, calc_rxstamp(), iax_frame::callno, jb_frame::data, ast_frame::delivery, ast_frame::frametype, iax2_frame_free(), iax2_lock_owner(), IAX_FORCEJITTERBUF, IAX_USEJITTERBUF, chan_iax2_pvt::jb, JB_DROP, jb_getall(), JB_OK, jb_put(), jb_reset(), JB_SCHED, JB_TYPE_CONTROL, JB_TYPE_SILENCE, JB_TYPE_VOICE, chan_iax2_pvt::jbid, len(), chan_iax2_pvt::owner, ast_channel_tech::properties, chan_iax2_pvt::rxcore, ast_frame::subclass, ast_channel::tech, iax_frame::ts, type, unwrap_timestamp(), and update_jbsched().

Referenced by socket_process(), and socket_process_meta().

{
   int type, len;
   int ret;
   int needfree = 0;
   struct ast_channel *owner = NULL;
   struct ast_channel *bridge = NULL;
   
   /* Attempt to recover wrapped timestamps */
   unwrap_timestamp(fr);

   /* delivery time is sender's sent timestamp converted back into absolute time according to our clock */
   if ( !fromtrunk && !ast_tvzero(iaxs[fr->callno]->rxcore))
      fr->af.delivery = ast_tvadd(iaxs[fr->callno]->rxcore, ast_samp2tv(fr->ts, 1000));
   else {
#if 0
      ast_debug(1, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
#endif
      fr->af.delivery = ast_tv(0,0);
   }

   type = JB_TYPE_CONTROL;
   len = 0;

   if(fr->af.frametype == AST_FRAME_VOICE) {
      type = JB_TYPE_VOICE;
      len = ast_codec_get_samples(&fr->af) / (ast_format_rate(fr->af.subclass) / 1000);
   } else if(fr->af.frametype == AST_FRAME_CNG) {
      type = JB_TYPE_SILENCE;
   }

   if ( (!ast_test_flag(iaxs[fr->callno], IAX_USEJITTERBUF)) ) {
      if (tsout)
         *tsout = fr->ts;
      __do_deliver(fr);
      return -1;
   }

   iax2_lock_owner(fr->callno);
   if (!iaxs[fr->callno]) {
      /* The call dissappeared so discard this frame that we could not send. */
      iax2_frame_free(fr);
      return -1;
   }
   if ((owner = iaxs[fr->callno]->owner))
      bridge = ast_bridged_channel(owner);

   /* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
    * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
   if ( (!ast_test_flag(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
      jb_frame frame;

      ast_channel_unlock(owner);

      /* deliver any frames in the jb */
      while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
         __do_deliver(frame.data);
         /* __do_deliver() can make the call disappear */
         if (!iaxs[fr->callno])
            return -1;
      }

      jb_reset(iaxs[fr->callno]->jb);

      ast_sched_thread_del(sched, iaxs[fr->callno]->jbid);

      /* deliver this frame now */
      if (tsout)
         *tsout = fr->ts;
      __do_deliver(fr);
      return -1;
   }
   if (owner) {
      ast_channel_unlock(owner);
   }

   /* insert into jitterbuffer */
   /* TODO: Perhaps we could act immediately if it's not droppable and late */
   ret = jb_put(iaxs[fr->callno]->jb, fr, type, len, fr->ts,
         calc_rxstamp(iaxs[fr->callno],fr->ts));
   if (ret == JB_DROP) {
      needfree++;
   } else if (ret == JB_SCHED) {
      update_jbsched(iaxs[fr->callno]);
   }
   if (tsout)
      *tsout = fr->ts;
   if (needfree) {
      /* Free our iax frame */
      iax2_frame_free(fr);
      return -1;
   }
   return 0;
}
static int scheduled_destroy ( const void *  vid) [static]

Definition at line 1693 of file chan_iax2.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), iax2_destroy(), LOG_DEBUG, option_debug, and PTR_TO_CALLNO.

Referenced by iax2_hangup().

{
   unsigned short callno = PTR_TO_CALLNO(vid);
   ast_mutex_lock(&iaxsl[callno]);
   if (iaxs[callno]) {
      if (option_debug) {
         ast_log(LOG_DEBUG, "Really destroying %d now...\n", callno);
      }
      iax2_destroy(callno);
   }
   ast_mutex_unlock(&iaxsl[callno]);
   return 0;
}
static int send_apathetic_reply ( unsigned short  callno,
unsigned short  dcallno,
struct sockaddr_in *  sin,
int  command,
int  ts,
unsigned char  seqno,
int  sockfd,
struct iax_ie_data ied 
) [static]

Definition at line 4507 of file chan_iax2.c.

References AST_FRAME_IAX, iax_ie_data::buf, compress_subclass(), and iax_ie_data::pos.

Referenced by handle_call_token(), and socket_process().

{
   struct {
      struct ast_iax2_full_hdr f;
      struct iax_ie_data ied;
   } data;
   size_t size = sizeof(struct ast_iax2_full_hdr);

   if (ied) {
      size += ied->pos;
      memcpy(&data.ied, ied->buf, ied->pos);
   }

   data.f.scallno = htons(0x8000 | callno);
   data.f.dcallno = htons(dcallno);
   data.f.ts = htonl(ts);
   data.f.iseqno = seqno;
   data.f.oseqno = 0;
   data.f.type = AST_FRAME_IAX;
   data.f.csub = compress_subclass(command);

   return sendto(sockfd, &data, size, 0, (struct sockaddr *)sin, sizeof(*sin));
}
static int send_command ( struct chan_iax2_pvt i,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen,
int  seqno 
) [static]
static int send_command_final ( struct chan_iax2_pvt i,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen,
int  seqno 
) [static]
Note:
Since this function calls iax2_predestroy() -> iax2_queue_hangup(), the pvt struct for the given call number may disappear during its execution.

Definition at line 7200 of file chan_iax2.c.

References __send_command(), chan_iax2_pvt::callno, and iax2_predestroy().

Referenced by __auth_reject(), __auto_hangup(), authenticate_request(), iax2_hangup(), socket_process(), and update_registry().

{
   int call_num = i->callno;
   /* It is assumed that the callno has already been locked */
   iax2_predestroy(i->callno);
   if (!iaxs[call_num])
      return -1;
   return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
}
static int send_command_immediate ( struct chan_iax2_pvt i,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen,
int  seqno 
) [static]

Definition at line 7210 of file chan_iax2.c.

References __send_command().

Referenced by iax2_vnak(), and socket_process().

{
   return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
}
static int send_command_locked ( unsigned short  callno,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen,
int  seqno 
) [static]

Definition at line 7186 of file chan_iax2.c.

References ast_mutex_lock(), ast_mutex_unlock(), and send_command().

Referenced by iax2_answer(), iax2_digit_begin(), iax2_digit_end(), iax2_sendhtml(), iax2_sendimage(), iax2_sendtext(), iax2_setoption(), and iax2_transfer().

{
   int res;
   ast_mutex_lock(&iaxsl[callno]);
   res = send_command(iaxs[callno], type, command, ts, data, datalen, seqno);
   ast_mutex_unlock(&iaxsl[callno]);
   return res;
}
static int send_command_transfer ( struct chan_iax2_pvt i,
char  type,
int  command,
unsigned int  ts,
const unsigned char *  data,
int  datalen 
) [static]

Definition at line 7215 of file chan_iax2.c.

References __send_command().

Referenced by socket_process(), and try_transfer().

{
   return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
}
static int send_lagrq ( const void *  data) [static]

Definition at line 1491 of file chan_iax2.c.

References __send_lagrq(), and schedule_action.

Referenced by __find_callno(), __send_lagrq(), and make_trunk().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__send_lagrq, data))
#endif      
      __send_lagrq(data);
   
   return 0;
}
static int send_packet ( struct iax_frame f) [static]

Definition at line 3177 of file chan_iax2.c.

References chan_iax2_pvt::addr, iax2_trunk_peer::addr, ast_debug, ast_inet_ntoa(), iax_frame::callno, iax_frame::data, iax_frame::datalen, errno, handle_error(), iax_showframe(), chan_iax2_pvt::peercallno, iax2_trunk_peer::sockfd, chan_iax2_pvt::transfer, transfer, iax_frame::transfer, and iax_frame::ts.

Referenced by __attempt_transmit(), iax2_send(), network_thread(), and vnak_retransmit().

{
   int res;
   int callno = f->callno;

   /* Don't send if there was an error, but return error instead */
   if (!callno || !iaxs[callno] || iaxs[callno]->error)
       return -1;
   
   /* Called with iaxsl held */
   if (iaxdebug)
      ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
   
   if (f->transfer) {
      if (iaxdebug)
         iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
      res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer, sizeof(iaxs[callno]->transfer));
   } else {
      if (iaxdebug)
         iax_showframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
      res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr, sizeof(iaxs[callno]->addr));
   }
   if (res < 0) {
      if (iaxdebug)
         ast_debug(1, "Received error: %s\n", strerror(errno));
      handle_error();
   } else
      res = 0;

   return res;
}
static int send_ping ( const void *  data) [static]

Definition at line 1430 of file chan_iax2.c.

References __send_ping(), and schedule_action.

Referenced by __find_callno(), __send_ping(), and make_trunk().

{
#ifdef SCHED_MULTITHREADED
   if (schedule_action(__send_ping, data))
#endif      
      __send_ping(data);

   return 0;
}
static void send_signaling ( struct chan_iax2_pvt pvt) [static]

This function must be called once we are sure the other side has given us a call number. All signaling is held here until that point.

Definition at line 1715 of file chan_iax2.c.

References AST_LIST_REMOVE_HEAD, signaling_queue_entry::f, free_signaling_queue_entry(), chan_iax2_pvt::hold_signaling, iax2_send(), s, and chan_iax2_pvt::signaling_queue.

Referenced by socket_process().

{
   struct signaling_queue_entry *s = NULL;

   while ((s = AST_LIST_REMOVE_HEAD(&pvt->signaling_queue, next))) {
      iax2_send(pvt, &s->f, 0, -1, 0, 0, 0);
      free_signaling_queue_entry(s);
   }
   pvt->hold_signaling = 0;
}
static int send_trunk ( struct iax2_trunk_peer tpeer,
struct timeval *  now 
) [static]

Definition at line 8770 of file chan_iax2.c.

References iax2_trunk_peer::addr, iax_frame::afdata, ast_debug, ast_inet_ntoa(), ast_test_flag, calc_txpeerstamp(), iax2_trunk_peer::calls, ast_iax2_meta_hdr::cmddata, iax_frame::data, ast_iax2_meta_hdr::data, iax_frame::datalen, iax_frame::direction, DIRECTION_OUTGRESS, IAX_META_TRUNK, IAX_META_TRUNK_MINI, IAX_META_TRUNK_SUPERMINI, IAX_TRUNKTIMESTAMPS, ast_iax2_meta_hdr::metacmd, iax_frame::retrans, iax2_trunk_peer::sockfd, iax_frame::transfer, transmit_trunk(), iax2_trunk_peer::trunkdata, iax2_trunk_peer::trunkdatalen, ast_iax2_meta_trunk_hdr::ts, and ast_iax2_meta_hdr::zeros.

Referenced by iax2_trunk_queue(), and timing_read().

{
   int res = 0;
   struct iax_frame *fr;
   struct ast_iax2_meta_hdr *meta;
   struct ast_iax2_meta_trunk_hdr *mth;
   int calls = 0;
   
   /* Point to frame */
   fr = (struct iax_frame *)tpeer->trunkdata;
   /* Point to meta data */
   meta = (struct ast_iax2_meta_hdr *)fr->afdata;
   mth = (struct ast_iax2_meta_trunk_hdr *)meta->data;
   if (tpeer->trunkdatalen) {
      /* We're actually sending a frame, so fill the meta trunk header and meta header */
      meta->zeros = 0;
      meta->metacmd = IAX_META_TRUNK;
      if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS))
         meta->cmddata = IAX_META_TRUNK_MINI;
      else
         meta->cmddata = IAX_META_TRUNK_SUPERMINI;
      mth->ts = htonl(calc_txpeerstamp(tpeer, trunkfreq, now));
      /* And the rest of the ast_iax2 header */
      fr->direction = DIRECTION_OUTGRESS;
      fr->retrans = -1;
      fr->transfer = 0;
      /* Any appropriate call will do */
      fr->data = fr->afdata;
      fr->datalen = tpeer->trunkdatalen + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr);
      res = transmit_trunk(fr, &tpeer->addr, tpeer->sockfd);
      calls = tpeer->calls;
#if 0
      ast_debug(1, "Trunking %d call chunks in %d bytes to %s:%d, ts=%d\n", calls, fr->datalen, ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), ntohl(mth->ts));
#endif      
      /* Reset transmit trunk side data */
      tpeer->trunkdatalen = 0;
      tpeer->calls = 0;
   }
   if (res < 0)
      return res;
   return calls;
}
static int set_config ( const char *  config_file,
int  reload 
) [static]

Load configuration.

Definition at line 12546 of file chan_iax2.c.

References add_calltoken_ignore(), ao2_link, ast_category_browse(), ast_cdr_amaflags2int(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_context_find_or_create(), ast_copy_string(), ast_false(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_netsock_bind(), ast_netsock_init(), ast_netsock_list_alloc(), ast_netsock_release(), ast_netsock_sockfd(), ast_netsock_unref(), ast_parse_allow_disallow(), ast_set2_flag, ast_set_flag, ast_set_flags_to, ast_str2cos(), ast_str2tos(), ast_strlen_zero(), ast_test_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, build_callno_limits(), build_peer(), build_user(), capability, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MAXCALLNO_LIMIT, DEFAULT_MAXCALLNO_LIMIT_NONVAL, DEFAULT_MAXMS, errno, format, gen, get_encrypt_methods(), iax2_capability, iax2_register(), IAX_ALLOWFWDOWNLOAD, IAX_CAPABILITY_FULLBANDWIDTH, IAX_CAPABILITY_LOWBANDWIDTH, IAX_CAPABILITY_MEDBANDWIDTH, IAX_CODEC_NOCAP, IAX_CODEC_NOPREFS, IAX_CODEC_USER_FIRST, IAX_DEFAULT_PORTNO, IAX_DEFAULT_REG_EXPIRE, IAX_DYNAMIC, IAX_FORCE_ENCRYPT, IAX_FORCEJITTERBUF, IAX_NOTRANSFER, IAX_RTAUTOCLEAR, IAX_RTCACHEFRIENDS, IAX_RTIGNOREREGEXPIRE, IAX_RTUPDATE, IAX_SHRINKCALLERID, IAX_TRANSFERMEDIA, IAX_TRUNKTIMESTAMPS, IAX_USEJITTERBUF, iaxmaxthreadcount, iaxthreadcount, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, max_reg_expire, MAX_TRUNK_MTU, MAX_TRUNKDATA, ast_variable::name, ast_variable::next, peer_unref(), prefs, qos, reg_source_db(), secret, set_config_destroy(), socket_read(), user, user_unref(), and ast_variable::value.

Referenced by load_module(), and reload_config().

{
   struct ast_config *cfg, *ucfg;
   int capability=iax2_capability;
   struct ast_variable *v;
   char *cat;
   const char *utype;
   const char *tosval;
   int format;
   int portno = IAX_DEFAULT_PORTNO;
   int  x;
   int mtuv; 
   struct iax2_user *user;
   struct iax2_peer *peer;
   struct ast_netsock *ns;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
#if 0
   static unsigned short int last_port=0;
#endif

   cfg = ast_config_load(config_file, config_flags);

   if (!cfg) {
      ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
      return -1;
   } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      ucfg = ast_config_load("users.conf", config_flags);
      if (ucfg == CONFIG_STATUS_FILEUNCHANGED)
         return 0;
      /* Otherwise we need to reread both files */
      ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
      if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEINVALID) {
         ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config_file);
         ast_config_destroy(ucfg);
         return 0;
      }
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config_file);
      return 0;
   } else { /* iax.conf changed, gotta reread users.conf, too */
      ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
      if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
         ast_log(LOG_ERROR, "Config file users.conf is in an invalid format.  Aborting.\n");
         ast_config_destroy(cfg);
         return 0;
      }
   }

   if (reload) {
      set_config_destroy();
   }

   /* Reset global codec prefs */   
   memset(&prefs, 0 , sizeof(struct ast_codec_pref));
   
   /* Reset Global Flags */
   memset(&globalflags, 0, sizeof(globalflags));
   ast_set_flag(&globalflags, IAX_RTUPDATE);
   ast_set_flag(&globalflags, IAX_SHRINKCALLERID);

#ifdef SO_NO_CHECK
   nochecksums = 0;
#endif
   /* Reset default parking lot */
   default_parkinglot[0] = '\0';

   min_reg_expire = IAX_DEFAULT_REG_EXPIRE;
   max_reg_expire = IAX_DEFAULT_REG_EXPIRE;
   global_max_trunk_mtu = MAX_TRUNK_MTU;
   global_maxcallno = DEFAULT_MAXCALLNO_LIMIT;
   global_maxcallno_nonval = DEFAULT_MAXCALLNO_LIMIT_NONVAL;

   maxauthreq = 3;

   srvlookup = 0;

   v = ast_variable_browse(cfg, "general");

   /* Seed initial tos value */
   tosval = ast_variable_retrieve(cfg, "general", "tos");
   if (tosval) {
      if (ast_str2tos(tosval, &qos.tos))
         ast_log(LOG_WARNING, "Invalid tos value, refer to QoS documentation\n");
   }
   /* Seed initial cos value */
   tosval = ast_variable_retrieve(cfg, "general", "cos");
   if (tosval) {
      if (ast_str2cos(tosval, &qos.cos))
         ast_log(LOG_WARNING, "Invalid cos value, refer to QoS documentation\n");
   }
   while(v) {
      if (!strcasecmp(v->name, "bindport")){ 
         if (reload)
            ast_log(LOG_NOTICE, "Ignoring bindport on reload\n");
         else
            portno = atoi(v->value);
      } else if (!strcasecmp(v->name, "pingtime")) 
         ping_time = atoi(v->value);
      else if (!strcasecmp(v->name, "iaxthreadcount")) {
         if (reload) {
            if (atoi(v->value) != iaxthreadcount)
               ast_log(LOG_NOTICE, "Ignoring any changes to iaxthreadcount during reload\n");
         } else {
            iaxthreadcount = atoi(v->value);
            if (iaxthreadcount < 1) {
               ast_log(LOG_NOTICE, "iaxthreadcount must be at least 1.\n");
               iaxthreadcount = 1;
            } else if (iaxthreadcount > 256) {
               ast_log(LOG_NOTICE, "limiting iaxthreadcount to 256\n");
               iaxthreadcount = 256;
            }
         }
      } else if (!strcasecmp(v->name, "iaxmaxthreadcount")) {
         if (reload) {
            AST_LIST_LOCK(&dynamic_list);
            iaxmaxthreadcount = atoi(v->value);
            AST_LIST_UNLOCK(&dynamic_list);
         } else {
            iaxmaxthreadcount = atoi(v->value);
            if (iaxmaxthreadcount < 0) {
               ast_log(LOG_NOTICE, "iaxmaxthreadcount must be at least 0.\n");
               iaxmaxthreadcount = 0;
            } else if (iaxmaxthreadcount > 256) {
               ast_log(LOG_NOTICE, "Limiting iaxmaxthreadcount to 256\n");
               iaxmaxthreadcount = 256;
            }
         }
      } else if (!strcasecmp(v->name, "nochecksums")) {
#ifdef SO_NO_CHECK
         if (ast_true(v->value))
            nochecksums = 1;
         else
            nochecksums = 0;
#else
         if (ast_true(v->value))
            ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
#endif
      }
      else if (!strcasecmp(v->name, "maxjitterbuffer")) 
         maxjitterbuffer = atoi(v->value);
      else if (!strcasecmp(v->name, "resyncthreshold")) 
         resyncthreshold = atoi(v->value);
      else if (!strcasecmp(v->name, "maxjitterinterps")) 
         maxjitterinterps = atoi(v->value);
      else if (!strcasecmp(v->name, "jittertargetextra"))
         jittertargetextra = atoi(v->value);
      else if (!strcasecmp(v->name, "lagrqtime")) 
         lagrq_time = atoi(v->value);
      else if (!strcasecmp(v->name, "maxregexpire")) 
         max_reg_expire = atoi(v->value);
      else if (!strcasecmp(v->name, "minregexpire")) 
         min_reg_expire = atoi(v->value);
      else if (!strcasecmp(v->name, "bindaddr")) {
         if (reload) {
            ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
         } else {
            if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, qos.tos, qos.cos, socket_read, NULL))) {
               ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno);
            } else {
                  if (strchr(v->value, ':'))
                  ast_verb(2, "Binding IAX2 to '%s'\n", v->value);
                  else
                  ast_verb(2, "Binding IAX2 to '%s:%d'\n", v->value, portno);
               if (defaultsockfd < 0) 
                  defaultsockfd = ast_netsock_sockfd(ns);
               ast_netsock_unref(ns);
            }
         }
      } else if (!strcasecmp(v->name, "authdebug")) {
         authdebug = ast_true(v->value);
      } else if (!strcasecmp(v->name, "encryption")) {
            iax2_encryption |= get_encrypt_methods(v->value);
            if (!iax2_encryption) {
               ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT);
            }
      } else if (!strcasecmp(v->name, "forceencryption")) {
         if (ast_false(v->value)) {
            ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT);
         } else {
            iax2_encryption |= get_encrypt_methods(v->value);
            if (iax2_encryption) {
               ast_set_flag((&globalflags), IAX_FORCE_ENCRYPT);
            }
         }
      } else if (!strcasecmp(v->name, "transfer")) {
         if (!strcasecmp(v->value, "mediaonly")) {
            ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); 
         } else if (ast_true(v->value)) {
            ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
         } else 
            ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
      } else if (!strcasecmp(v->name, "codecpriority")) {
         if(!strcasecmp(v->value, "caller"))
            ast_set_flag((&globalflags), IAX_CODEC_USER_FIRST);
         else if(!strcasecmp(v->value, "disabled"))
            ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
         else if(!strcasecmp(v->value, "reqonly")) {
            ast_set_flag((&globalflags), IAX_CODEC_NOCAP);
            ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
         }
      } else if (!strcasecmp(v->name, "jitterbuffer"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_USEJITTERBUF); 
      else if (!strcasecmp(v->name, "forcejitterbuffer"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);  
      else if (!strcasecmp(v->name, "delayreject"))
         delayreject = ast_true(v->value);
      else if (!strcasecmp(v->name, "allowfwdownload"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_ALLOWFWDOWNLOAD);
      else if (!strcasecmp(v->name, "rtcachefriends"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);  
      else if (!strcasecmp(v->name, "rtignoreregexpire"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTIGNOREREGEXPIRE);  
      else if (!strcasecmp(v->name, "rtupdate"))
         ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTUPDATE);
      else if (!strcasecmp(v->name, "trunktimestamps"))
         ast_set2_flag(&globalflags, ast_true(v->value), IAX_TRUNKTIMESTAMPS);
      else if (!strcasecmp(v->name, "rtautoclear")) {
         int i = atoi(v->value);
         if(i > 0)
            global_rtautoclear = i;
         else
            i = 0;
         ast_set2_flag((&globalflags), i || ast_true(v->value), IAX_RTAUTOCLEAR);   
      } else if (!strcasecmp(v->name, "trunkfreq")) {
         trunkfreq = atoi(v->value);
         if (trunkfreq < 10)
            trunkfreq = 10;
      } else if (!strcasecmp(v->name, "trunkmtu")) {
         mtuv = atoi(v->value);
         if (mtuv  == 0 )  
            global_max_trunk_mtu = 0; 
         else if (mtuv >= 172 && mtuv < 4000) 
            global_max_trunk_mtu = mtuv; 
         else 
            ast_log(LOG_NOTICE, "trunkmtu value out of bounds (%d) at line %d\n",
               mtuv, v->lineno);
      } else if (!strcasecmp(v->name, "trunkmaxsize")) {
         trunkmaxsize = atoi(v->value);
         if (trunkmaxsize == 0)
            trunkmaxsize = MAX_TRUNKDATA;
      } else if (!strcasecmp(v->name, "autokill")) {
         if (sscanf(v->value, "%30d", &x) == 1) {
            if (x >= 0)
               autokill = x;
            else
               ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
         } else if (ast_true(v->value)) {
            autokill = DEFAULT_MAXMS;
         } else {
            autokill = 0;
         }
      } else if (!strcasecmp(v->name, "bandwidth")) {
         if (!strcasecmp(v->value, "low")) {
            capability = IAX_CAPABILITY_LOWBANDWIDTH;
         } else if (!strcasecmp(v->value, "medium")) {
            capability = IAX_CAPABILITY_MEDBANDWIDTH;
         } else if (!strcasecmp(v->value, "high")) {
            capability = IAX_CAPABILITY_FULLBANDWIDTH;
         } else
            ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
      } else if (!strcasecmp(v->name, "allow")) {
         ast_parse_allow_disallow(&prefs, &capability, v->value, 1);
      } else if (!strcasecmp(v->name, "disallow")) {
         ast_parse_allow_disallow(&prefs, &capability, v->value, 0);
      } else if (!strcasecmp(v->name, "register")) {
         iax2_register(v->value, v->lineno);
      } else if (!strcasecmp(v->name, "iaxcompat")) {
         iaxcompat = ast_true(v->value);
      } else if (!strcasecmp(v->name, "regcontext")) {
         ast_copy_string(regcontext, v->value, sizeof(regcontext));
         /* Create context if it doesn't exist already */
         ast_context_find_or_create(NULL, NULL, regcontext, "IAX2");
      } else if (!strcasecmp(v->name, "tos")) {
         if (ast_str2tos(v->value, &qos.tos))
            ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
      } else if (!strcasecmp(v->name, "cos")) {
         if (ast_str2cos(v->value, &qos.cos))
            ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
      } else if (!strcasecmp(v->name, "parkinglot")) {
         ast_copy_string(default_parkinglot, v->value, sizeof(default_parkinglot));
      } else if (!strcasecmp(v->name, "accountcode")) {
         ast_copy_string(accountcode, v->value, sizeof(accountcode));
      } else if (!strcasecmp(v->name, "mohinterpret")) {
         ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
      } else if (!strcasecmp(v->name, "mohsuggest")) {
         ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
      } else if (!strcasecmp(v->name, "amaflags")) {
         format = ast_cdr_amaflags2int(v->value);
         if (format < 0) {
            ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
         } else {
            amaflags = format;
         }
      } else if (!strcasecmp(v->name, "language")) {
         ast_copy_string(language, v->value, sizeof(language));
      } else if (!strcasecmp(v->name, "maxauthreq")) {
         maxauthreq = atoi(v->value);
         if (maxauthreq < 0)
            maxauthreq = 0;
      } else if (!strcasecmp(v->name, "adsi")) {
         adsi = ast_true(v->value);
      } else if (!strcasecmp(v->name, "srvlookup")) {
         srvlookup = ast_true(v->value);
      } else if (!strcasecmp(v->name, "maxcallnumbers")) {
         if (sscanf(v->value, "%10hu", &global_maxcallno) != 1) {
            ast_log(LOG_WARNING, "maxcallnumbers must be set to a valid number.  %s is not valid at line %d\n", v->value, v->lineno);
         }
      } else if (!strcasecmp(v->name, "maxcallnumbers_nonvalidated")) {
         if (sscanf(v->value, "%10hu", &global_maxcallno_nonval) != 1) {
            ast_log(LOG_WARNING, "maxcallnumbers_nonvalidated must be set to a valid number.  %s is not valid at line %d.\n", v->value, v->lineno);
         }
      } else if (!strcasecmp(v->name, "calltokenoptional")) {
         if (add_calltoken_ignore(v->value)) {
            ast_log(LOG_WARNING, "Invalid calltokenoptional address range - '%s' line %d\n", v->value, v->lineno);
         }
      } else if (!strcasecmp(v->name, "shrinkcallerid")) {
         if (ast_true(v->value)) {
            ast_set_flag((&globalflags), IAX_SHRINKCALLERID);
         } else if (ast_false(v->value)) {
            ast_clear_flag((&globalflags), IAX_SHRINKCALLERID);
         } else {
            ast_log(LOG_WARNING, "shrinkcallerid value %s is not valid at line %d.\n", v->value, v->lineno);
         }
      }/*else if (strcasecmp(v->name,"type")) */
      /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
      v = v->next;
   }
   
   if (defaultsockfd < 0) {
      if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, qos.tos, qos.cos, socket_read, NULL))) {
         ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
      } else {
         ast_verb(2, "Binding IAX2 to default address 0.0.0.0:%d\n", portno);
         defaultsockfd = ast_netsock_sockfd(ns);
         ast_netsock_unref(ns);
      }
   }
   if (reload) {
      ast_netsock_release(outsock);
      outsock = ast_netsock_list_alloc();
      if (!outsock) {
         ast_log(LOG_ERROR, "Could not allocate outsock list.\n");
         return -1;
      }
      ast_netsock_init(outsock);
   }

   if (min_reg_expire > max_reg_expire) {
      ast_log(LOG_WARNING, "Minimum registration interval of %d is more than maximum of %d, resetting minimum to %d\n",
         min_reg_expire, max_reg_expire, max_reg_expire);
      min_reg_expire = max_reg_expire;
   }
   iax2_capability = capability;
   
   if (ucfg) {
      struct ast_variable *gen;
      int genhasiax;
      int genregisteriax;
      const char *hasiax, *registeriax;
      
      genhasiax = ast_true(ast_variable_retrieve(ucfg, "general", "hasiax"));
      genregisteriax = ast_true(ast_variable_retrieve(ucfg, "general", "registeriax"));
      gen = ast_variable_browse(ucfg, "general");
      cat = ast_category_browse(ucfg, NULL);
      while (cat) {
         if (strcasecmp(cat, "general")) {
            hasiax = ast_variable_retrieve(ucfg, cat, "hasiax");
            registeriax = ast_variable_retrieve(ucfg, cat, "registeriax");
            if (ast_true(hasiax) || (!hasiax && genhasiax)) {
               /* Start with general parameters, then specific parameters, user and peer */
               user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
               if (user) {
                  ao2_link(users, user);
                  user = user_unref(user);
               }
               peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
               if (peer) {
                  if (ast_test_flag(peer, IAX_DYNAMIC))
                     reg_source_db(peer);
                  ao2_link(peers, peer);
                  peer = peer_unref(peer);
               }
            }
            if (ast_true(registeriax) || (!registeriax && genregisteriax)) {
               char tmp[256];
               const char *host = ast_variable_retrieve(ucfg, cat, "host");
               const char *username = ast_variable_retrieve(ucfg, cat, "username");
               const char *secret = ast_variable_retrieve(ucfg, cat, "secret");
               if (!host)
                  host = ast_variable_retrieve(ucfg, "general", "host");
               if (!username)
                  username = ast_variable_retrieve(ucfg, "general", "username");
               if (!secret)
                  secret = ast_variable_retrieve(ucfg, "general", "secret");
               if (!ast_strlen_zero(username) && !ast_strlen_zero(host)) {
                  if (!ast_strlen_zero(secret))
                     snprintf(tmp, sizeof(tmp), "%s:%s@%s", username, secret, host);
                  else
                     snprintf(tmp, sizeof(tmp), "%s@%s", username, host);
                  iax2_register(tmp, 0);
               }
            }
         }
         cat = ast_category_browse(ucfg, cat);
      }
      ast_config_destroy(ucfg);
   }
   
   cat = ast_category_browse(cfg, NULL);
   while(cat) {
      if (strcasecmp(cat, "general")) {
         utype = ast_variable_retrieve(cfg, cat, "type");
         if (!strcasecmp(cat, "callnumberlimits")) {
            build_callno_limits(ast_variable_browse(cfg, cat));
         } else if (utype) {
            if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
               user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
               if (user) {
                  ao2_link(users, user);
                  user = user_unref(user);
               }
            }
            if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
               peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
               if (peer) {
                  if (ast_test_flag(peer, IAX_DYNAMIC))
                     reg_source_db(peer);
                  ao2_link(peers, peer);
                  peer = peer_unref(peer);
               }
            } else if (strcasecmp(utype, "user")) {
               ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config_file);
            }
         } else
            ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
      }
      cat = ast_category_browse(cfg, cat);
   }
   ast_config_destroy(cfg);
   return 1;
}
static void set_peercnt_limit ( struct peercnt peercnt) [static]

Definition at line 2127 of file chan_iax2.c.

References peercnt::addr, addr_range_match_address_cb(), ao2_callback, ao2_ref, ast_debug, ast_inet_ntoa(), global_maxcallno, addr_range::limit, peercnt::limit, and peercnt::reg.

Referenced by peercnt_add(), peercnt_modify(), and set_peercnt_limit_all_cb().

{
   uint16_t limit = global_maxcallno;
   struct addr_range *addr_range;
   struct sockaddr_in sin = {
      .sin_addr.s_addr = peercnt->addr,
   };


   if (peercnt->reg && peercnt->limit) {
      return; /* this peercnt has a custom limit set by a registration */
   }

   if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &sin))) {
      limit = addr_range->limit;
      ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_inet_ntoa(sin.sin_addr));
      ao2_ref(addr_range, -1);
   }

   peercnt->limit = limit;
}
static int set_peercnt_limit_all_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 2153 of file chan_iax2.c.

References ast_debug, and set_peercnt_limit().

Referenced by reload_config().

{
   struct peercnt *peercnt = obj;

   set_peercnt_limit(peercnt);
   ast_debug(1, "Reset limits for peercnts table\n");

   return 0;
}
static void signal_condition ( ast_mutex_t lock,
ast_cond_t cond 
) [static]
static int socket_process ( struct iax2_thread thread) [static]

Definition at line 9493 of file chan_iax2.c.

References chan_iax2_pvt::addr, iax_frame::af, iax_frame::afdatalen, chan_iax2_pvt::aseqno, ast_async_goto(), ast_best_codec(), ast_bridged_channel(), ast_calloc, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_FACILITY_NOT_SUBSCRIBED, AST_CAUSE_NO_ROUTE_DESTINATION, ast_channel_datastore_add(), ast_channel_unlock, ast_clear_flag, ast_codec_choose(), ast_codec_get_samples(), ast_codec_pref_convert(), ast_codec_pref_index(), ast_codec_pref_string(), AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_PROGRESS, AST_CONTROL_UNHOLD, ast_datastore_alloc(), ast_datastore_free(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_exists_extension(), AST_FORMAT_SLINEAR, ast_frame_byteswap_be, AST_FRAME_CONTROL, AST_FRAME_IAX, AST_FRAME_NULL, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_free, ast_getformatname(), ast_iax2_new(), ast_inet_ntoa(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_parking_ext(), ast_sched_thread_del, ast_set_flag, ast_set_read_format(), ast_set_write_format(), AST_STATE_RING, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_var_assign(), ast_variables_destroy(), ast_verb, auth_fail(), authenticate_reply(), authenticate_request(), authenticate_verify(), chan_iax2_pvt::authmethods, iax_ie_data::buf, iax2_thread::buf, iax2_thread::buf_len, CACHE_FLAG_TRANSMITTED, iax_frame::cacheable, calc_timestamp(), iax_ies::called_number, iax2_peer::callno, chan_iax2_pvt::callno, iax_frame::callno, iax_ies::calltoken, iax_ies::calltokendata, chan_iax2_pvt::capability, iax_ies::cause, iax_ies::causecode, iax_ies::challenge, check_access(), check_provisioning(), chan_iax2_pvt::chosenformat, chan_iax2_pvt::cid_num, cid_num, iax_ies::codec_prefs, complete_dpreply(), complete_transfer(), construct_rr(), context, chan_iax2_pvt::context, ast_iax2_full_hdr::csub, ast_datastore::data, ast_frame::data, ast_frame::datalen, DATASTORE_INHERIT_FOREVER, ast_iax2_full_hdr::dcallno, decrypt_frame(), iax_ies::devicetype, dp_lookup(), chan_iax2_pvt::encmethods, iax_ies::encmethods, ast_var_t::entries, chan_iax2_pvt::error, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, exists(), exten, chan_iax2_pvt::exten, iax_frame::final, find_callno(), chan_iax2_pvt::first_iax_message, iax2_dpcache::flags, iax_ies::format, format, chan_iax2_pvt::frames_received, ast_frame::frametype, iax_ies::fwdesc, handle_call_token(), ast_channel::hangupcause, iax2_peer::historicms, chan_iax2_pvt::hold_signaling, iax2_ack_registry(), iax2_allow_new(), iax2_destroy(), iax2_dprequest(), iax2_lock_owner(), iax2_poke_peer_s(), iax2_queue_control_data(), iax2_queue_frame(), iax2_sched_add(), iax2_send(), iax2_vnak(), IAX_ALLOWFWDOWNLOAD, IAX_ALREADYGONE, IAX_AUTH_MD5, IAX_CALLENCRYPTED, IAX_CODEC_NOCAP, IAX_CODEC_NOPREFS, IAX_CODEC_USER_FIRST, IAX_COMMAND_ACCEPT, IAX_COMMAND_ACK, IAX_COMMAND_AUTHREP, IAX_COMMAND_AUTHREQ, IAX_COMMAND_CALLTOKEN, IAX_COMMAND_DIAL, IAX_COMMAND_DPREP, IAX_COMMAND_DPREQ, IAX_COMMAND_FWDATA, IAX_COMMAND_FWDOWNL, IAX_COMMAND_HANGUP, IAX_COMMAND_INVAL, IAX_COMMAND_LAGRP, IAX_COMMAND_LAGRQ, IAX_COMMAND_NEW, IAX_COMMAND_PING, IAX_COMMAND_POKE, IAX_COMMAND_PONG, IAX_COMMAND_QUELCH, IAX_COMMAND_REGACK, IAX_COMMAND_REGAUTH, IAX_COMMAND_REGREJ, IAX_COMMAND_REGREL, IAX_COMMAND_REGREQ, IAX_COMMAND_REJECT, IAX_COMMAND_RTKEY, IAX_COMMAND_TRANSFER, IAX_COMMAND_TXACC, IAX_COMMAND_TXCNT, IAX_COMMAND_TXMEDIA, IAX_COMMAND_TXREADY, IAX_COMMAND_TXREJ, IAX_COMMAND_TXREL, IAX_COMMAND_TXREQ, IAX_COMMAND_UNQUELCH, IAX_COMMAND_UNSUPPORT, IAX_COMMAND_VNAK, IAX_DEBUGDIGEST, IAX_DELAYPBXSTART, IAX_ENCRYPTED, iax_firmware_append(), IAX_FLAG_FULL, IAX_FLAG_RETRANS, IAX_FORCE_ENCRYPT, iax_frame_wrap(), iax_ie_append_byte(), iax_ie_append_int(), iax_ie_append_short(), iax_ie_append_str(), IAX_IE_CALLNO, IAX_IE_CAUSE, IAX_IE_CAUSECODE, IAX_IE_FORMAT, IAX_IE_IAX_UNKNOWN, IAX_IMMEDIATE, iax_outputframe(), iax_park(), iax_parse_ies(), IAX_PROVISION, IAX_QUELCH, IAX_STATE_AUTHENTICATED, IAX_STATE_STARTED, IAX_STATE_TBD, IAX_TRUNK, iax_ies::iax_unknown, iaxfrdup2(), chan_iax2_pvt::iaxvars, inaddrcmp(), ast_datastore::inheritance, chan_iax2_pvt::initid, chan_iax2_pvt::inkeys, iax2_thread::iofd, iax2_thread::iosin, chan_iax2_pvt::iseqno, iax_frame::iseqno, ast_iax2_full_hdr::iseqno, chan_iax2_pvt::last, chan_iax2_pvt::last_iax_message, iax2_peer::lastms, ast_frame::len, LOG_ERROR, log_jitterstats(), LOG_NOTICE, LOG_WARNING, make_trunk(), ast_frame::mallocd, manager_event, iax2_peer::maxms, merge_encryption(), ast_iax2_meta_hdr::metacmd, chan_iax2_pvt::mohsuggest, iax_ies::musiconhold, iax2_peer::name, ast_channel::name, ast_variable::name, ast_channel::nativeformats, NEW_ALLOW, NEW_ALLOW_CALLTOKEN_VALIDATED, NEW_PREVENT, ast_variable::next, ast_frame::offset, chan_iax2_pvt::oseqno, iax_frame::oseqno, ast_iax2_full_hdr::oseqno, iax_frame::outoforder, chan_iax2_pvt::owner, pbx_builtin_setvar_helper(), peer_ref(), peer_unref(), chan_iax2_pvt::peercallno, chan_iax2_pvt::peercapability, chan_iax2_pvt::peerformat, iax2_peer::pokeexpire, iax2_peer::pokefreqnotok, iax2_peer::pokefreqok, iax_ie_data::pos, chan_iax2_pvt::prefs, iax_ies::provver, iax_ies::provverpres, ast_frame::ptr, raw_hangup(), ast_channel::readformat, iax_ies::refresh, REG_STATE_REJECTED, register_verify(), registry_authrequest(), registry_rerequest(), remove_by_peercallno(), resend_with_token(), iax_frame::retries, chan_iax2_pvt::rprefs, chan_iax2_pvt::rseqno, S_OR, ast_frame::samples, save_osptoken(), save_rr(), ast_iax2_full_hdr::scallno, schedule_delivery(), chan_iax2_pvt::secret, send_apathetic_reply(), send_command(), send_command_final(), send_command_immediate(), send_command_transfer(), send_signaling(), iax_ies::serviceident, iax2_peer::smoothing, socket_process_meta(), spawn_dp_lookup(), ast_frame::src, chan_iax2_pvt::state, stop_stuff(), store_by_peercallno(), ast_frame::subclass, iax_frame::transfer, TRANSFER_BEGIN, TRANSFER_MBEGIN, TRANSFER_MEDIA, TRANSFER_MEDIAPASS, TRANSFER_MREADY, TRANSFER_READY, TRANSFER_RELEASED, chan_iax2_pvt::transferring, try_transfer(), iax_frame::ts, ast_iax2_full_hdr::ts, ast_iax2_full_hdr::type, uncompress_subclass(), ast_channel::uniqueid, update_registry(), iax_ies::username, ast_variable::value, var, iax_ies::vars, VERBOSE_PREFIX_4, chan_iax2_pvt::videoformat, vnak_retransmit(), chan_iax2_pvt::voiceformat, and ast_iax2_meta_hdr::zeros.

Referenced by handle_deferred_full_frames(), and iax2_process_thread().

{
   struct sockaddr_in sin;
   int res;
   int updatehistory=1;
   int new = NEW_PREVENT;
   int dcallno = 0;
   char decrypted = 0;
   struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)thread->buf;
   struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)thread->buf;
   struct ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_hdr *)thread->buf;
   struct ast_iax2_video_hdr *vh = (struct ast_iax2_video_hdr *)thread->buf;
   struct iax_frame *fr;
   struct iax_frame *cur;
   struct ast_frame f = { 0, };
   struct ast_channel *c = NULL;
   struct iax2_dpcache *dp;
   struct iax2_peer *peer;
   struct iax_ies ies;
   struct iax_ie_data ied0, ied1;
   int format;
   int fd;
   int exists;
   int minivid = 0;
   char empty[32]="";      /* Safety measure */
   struct iax_frame *duped_fr;
   char host_pref_buf[128];
   char caller_pref_buf[128];
   struct ast_codec_pref pref;
   char *using_prefs = "mine";

   /* allocate an iax_frame with 4096 bytes of data buffer */
   fr = alloca(sizeof(*fr) + 4096);
   memset(fr, 0, sizeof(*fr));
   fr->afdatalen = 4096; /* From alloca() above */

   /* Copy frequently used parameters to the stack */
   res = thread->buf_len;
   fd = thread->iofd;
   memcpy(&sin, &thread->iosin, sizeof(sin));

   if (res < sizeof(*mh)) {
      ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
      return 1;
   }
   if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
      if (res < sizeof(*vh)) {
         ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a video frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
         return 1;
      }

      /* This is a video frame, get call number */
      fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
      minivid = 1;
   } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
      return socket_process_meta(res, meta, &sin, fd, fr);

#ifdef DEBUG_SUPPORT
   if (res >= sizeof(*fh))
      iax_outputframe(NULL, fh, 1, &sin, res - sizeof(*fh));
#endif
   if (ntohs(mh->callno) & IAX_FLAG_FULL) {
      if (res < sizeof(*fh)) {
         ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
         return 1;
      }

      /* Get the destination call number */
      dcallno = ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS;


      /* check to make sure this full frame isn't encrypted before we attempt
       * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
       * callno is not found here, that just means one hasn't been allocated for
       * this connection yet. */
      if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, NEW_PREVENT, fd, 1))) {
         ast_mutex_lock(&iaxsl[fr->callno]);
         if (iaxs[fr->callno] && ast_test_flag(iaxs[fr->callno], IAX_ENCRYPTED)) {
            if (decrypt_frame(fr->callno, fh, &f, &res)) {
               ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
               ast_mutex_unlock(&iaxsl[fr->callno]);
               return 1;
            }
            decrypted = 1;
         }
         ast_mutex_unlock(&iaxsl[fr->callno]);
      }

      /* Retrieve the type and subclass */
      f.frametype = fh->type;
      if (f.frametype == AST_FRAME_VIDEO) {
         f.subclass = uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1);
      } else {
         f.subclass = uncompress_subclass(fh->csub);
      }

      /* Deal with POKE/PONG without allocating a callno */
      if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_POKE) {
         /* Reply back with a PONG, but don't care about the result. */
         send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
         return 1;
      } else if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_ACK && dcallno == 1) {
         /* Ignore */
         return 1;
      }

      f.datalen = res - sizeof(*fh);
      if (f.datalen) {
         if (f.frametype == AST_FRAME_IAX) {
            if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
               ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
               ast_variables_destroy(ies.vars);
               return 1;
            }
            f.data.ptr = NULL;
            f.datalen = 0;
         } else {
            f.data.ptr = thread->buf + sizeof(struct ast_iax2_full_hdr);
            memset(&ies, 0, sizeof(ies));
         }
      } else {
         if (f.frametype == AST_FRAME_IAX)
            f.data.ptr = NULL;
         else
            f.data.ptr = empty;
         memset(&ies, 0, sizeof(ies));
      }

      if (!dcallno && iax2_allow_new(f.frametype, f.subclass, 1)) {
         /* only set NEW_ALLOW if calltoken checks out */
         if (handle_call_token(fh, &ies, &sin, fd)) {
            ast_variables_destroy(ies.vars);
            return 1;
         }

         if (ies.calltoken && ies.calltokendata) {
            /* if we've gotten this far, and the calltoken ie data exists,
             * then calltoken validation _MUST_ have taken place.  If calltoken
             * data is provided, it is always validated reguardless of any
             * calltokenoptional or requirecalltoken options */
            new = NEW_ALLOW_CALLTOKEN_VALIDATED;
         } else {
            new = NEW_ALLOW;
         }
      }
   } else {
      /* Don't know anything about it yet */
      f.frametype = AST_FRAME_NULL;
      f.subclass = 0;
      memset(&ies, 0, sizeof(ies));
   }

   if (!fr->callno) {
      int check_dcallno = 0;

      /*
       * We enforce accurate destination call numbers for ACKs.  This forces the other
       * end to know the destination call number before call setup can complete.
       *
       * Discussed in the following thread:
       *    http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html 
       */

      if ((ntohs(mh->callno) & IAX_FLAG_FULL) && ((f.frametype == AST_FRAME_IAX) && (f.subclass == IAX_COMMAND_ACK))) {
         check_dcallno = 1;
      }

      if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno))) {
         if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_NEW) {
            send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
         } else if (f.frametype == AST_FRAME_IAX && (f.subclass == IAX_COMMAND_REGREQ || f.subclass == IAX_COMMAND_REGREL)) {
            send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
         }
         ast_variables_destroy(ies.vars);
         return 1;
      }
   }

   if (fr->callno > 0)
      ast_mutex_lock(&iaxsl[fr->callno]);

   if (!fr->callno || !iaxs[fr->callno]) {
      /* A call arrived for a nonexistent destination.  Unless it's an "inval"
         frame, reply with an inval */
      if (ntohs(mh->callno) & IAX_FLAG_FULL) {
         /* We can only raw hangup control frames */
         if (((f.subclass != IAX_COMMAND_INVAL) &&
             (f.subclass != IAX_COMMAND_TXCNT) &&
             (f.subclass != IAX_COMMAND_TXACC) &&
             (f.subclass != IAX_COMMAND_FWDOWNL))||
             (f.frametype != AST_FRAME_IAX))
            raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
            fd);
      }
      if (fr->callno > 0) 
         ast_mutex_unlock(&iaxsl[fr->callno]);
      ast_variables_destroy(ies.vars);
      return 1;
   }
   if (ast_test_flag(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) {
      if (decrypt_frame(fr->callno, fh, &f, &res)) {
         ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
         ast_variables_destroy(ies.vars);
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }
      decrypted = 1;
   }
#ifdef DEBUG_SUPPORT
   if (decrypted) {
      iax_outputframe(NULL, fh, 3, &sin, res - sizeof(*fh));
   }
#endif

   /* count this frame */
   iaxs[fr->callno]->frames_received++;

   if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
      f.subclass != IAX_COMMAND_TXCNT &&     /* for attended transfer */
      f.subclass != IAX_COMMAND_TXACC) {     /* for attended transfer */
      unsigned short new_peercallno;
      
      new_peercallno = (unsigned short) (ntohs(mh->callno) & ~IAX_FLAG_FULL);
      if (new_peercallno && new_peercallno != iaxs[fr->callno]->peercallno) {
         if (iaxs[fr->callno]->peercallno) {
            remove_by_peercallno(iaxs[fr->callno]);
         }
         iaxs[fr->callno]->peercallno = new_peercallno;
         store_by_peercallno(iaxs[fr->callno]);
      }
   }
   if (ntohs(mh->callno) & IAX_FLAG_FULL) {
      if (iaxdebug)
         ast_debug(1, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
      /* Check if it's out of order (and not an ACK or INVAL) */
      fr->oseqno = fh->oseqno;
      fr->iseqno = fh->iseqno;
      fr->ts = ntohl(fh->ts);
#ifdef IAXTESTS
      if (test_resync) {
         ast_debug(1, "Simulating frame ts resync, was %u now %u\n", fr->ts, fr->ts + test_resync);
         fr->ts += test_resync;
      }
#endif /* IAXTESTS */
#if 0
      if ( (ntohs(fh->dcallno) & IAX_FLAG_RETRANS) ||
           ( (f.frametype != AST_FRAME_VOICE) && ! (f.frametype == AST_FRAME_IAX &&
                        (f.subclass == IAX_COMMAND_NEW ||
                         f.subclass == IAX_COMMAND_AUTHREQ ||
                         f.subclass == IAX_COMMAND_ACCEPT ||
                         f.subclass == IAX_COMMAND_REJECT))      ) )
#endif
      if ((ntohs(fh->dcallno) & IAX_FLAG_RETRANS) || (f.frametype != AST_FRAME_VOICE))
         updatehistory = 0;
      if ((iaxs[fr->callno]->iseqno != fr->oseqno) &&
         (iaxs[fr->callno]->iseqno ||
            ((f.subclass != IAX_COMMAND_TXCNT) &&
            (f.subclass != IAX_COMMAND_TXREADY) &&    /* for attended transfer */
            (f.subclass != IAX_COMMAND_TXREL) &&      /* for attended transfer */
            (f.subclass != IAX_COMMAND_UNQUELCH ) &&  /* for attended transfer */
            (f.subclass != IAX_COMMAND_TXACC)) ||
            (f.frametype != AST_FRAME_IAX))) {
         if (
          ((f.subclass != IAX_COMMAND_ACK) &&
           (f.subclass != IAX_COMMAND_INVAL) &&
           (f.subclass != IAX_COMMAND_TXCNT) &&
           (f.subclass != IAX_COMMAND_TXREADY) &&     /* for attended transfer */
           (f.subclass != IAX_COMMAND_TXREL) &&    /* for attended transfer */
           (f.subclass != IAX_COMMAND_UNQUELCH ) &&   /* for attended transfer */
           (f.subclass != IAX_COMMAND_TXACC) &&
           (f.subclass != IAX_COMMAND_VNAK)) ||
           (f.frametype != AST_FRAME_IAX)) {
            /* If it's not an ACK packet, it's out of order. */
            ast_debug(1, "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n", 
               iaxs[fr->callno]->iseqno, fr->oseqno, f.frametype, f.subclass);
            /* Check to see if we need to request retransmission,
             * and take sequence number wraparound into account */
            if ((unsigned char) (iaxs[fr->callno]->iseqno - fr->oseqno) < 128) {
               /* If we've already seen it, ack it XXX There's a border condition here XXX */
               if ((f.frametype != AST_FRAME_IAX) || 
                     ((f.subclass != IAX_COMMAND_ACK) && (f.subclass != IAX_COMMAND_INVAL))) {
                  ast_debug(1, "Acking anyway\n");
                  /* XXX Maybe we should handle its ack to us, but then again, it's probably outdated anyway, and if
                     we have anything to send, we'll retransmit and get an ACK back anyway XXX */
                  send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
               }
            } else {
               /* Send a VNAK requesting retransmission */
               iax2_vnak(fr->callno);
            }
            ast_variables_destroy(ies.vars);
            ast_mutex_unlock(&iaxsl[fr->callno]);
            return 1;
         }
      } else {
         /* Increment unless it's an ACK or VNAK */
         if (((f.subclass != IAX_COMMAND_ACK) &&
             (f.subclass != IAX_COMMAND_INVAL) &&
             (f.subclass != IAX_COMMAND_TXCNT) &&
             (f.subclass != IAX_COMMAND_TXACC) &&
            (f.subclass != IAX_COMMAND_VNAK)) ||
             (f.frametype != AST_FRAME_IAX))
            iaxs[fr->callno]->iseqno++;
      }
      /* Ensure text frames are NULL-terminated */
      if (f.frametype == AST_FRAME_TEXT && thread->buf[res - 1] != '\0') {
         if (res < thread->buf_size)
            thread->buf[res++] = '\0';
         else /* Trims one character from the text message, but that's better than overwriting the end of the buffer. */
            thread->buf[res - 1] = '\0';
      }

      /* Handle implicit ACKing unless this is an INVAL, and only if this is 
         from the real peer, not the transfer peer */
      if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && 
          ((f.subclass != IAX_COMMAND_INVAL) ||
           (f.frametype != AST_FRAME_IAX))) {
         unsigned char x;
         int call_to_destroy;
         /* First we have to qualify that the ACKed value is within our window */
         if (iaxs[fr->callno]->rseqno >= iaxs[fr->callno]->oseqno || (fr->iseqno >= iaxs[fr->callno]->rseqno && fr->iseqno < iaxs[fr->callno]->oseqno))
            x = fr->iseqno;
         else 
            x = iaxs[fr->callno]->oseqno;
         if ((x != iaxs[fr->callno]->oseqno) || (iaxs[fr->callno]->oseqno == fr->iseqno)) {
            /* The acknowledgement is within our window.  Time to acknowledge everything
               that it says to */
            for (x=iaxs[fr->callno]->rseqno; x != fr->iseqno; x++) {
               /* Ack the packet with the given timestamp */
               if (iaxdebug)
                  ast_debug(1, "Cancelling transmission of packet %d\n", x);
               call_to_destroy = 0;
               AST_LIST_LOCK(&frame_queue);
               AST_LIST_TRAVERSE(&frame_queue, cur, list) {
                  /* If it's our call, and our timestamp, mark -1 retries */
                  if ((fr->callno == cur->callno) && (x == cur->oseqno)) {
                     cur->retries = -1;
                     /* Destroy call if this is the end */
                     if (cur->final)
                        call_to_destroy = fr->callno;
                  }
               }
               AST_LIST_UNLOCK(&frame_queue);
               if (call_to_destroy) {
                  if (iaxdebug)
                     ast_debug(1, "Really destroying %d, having been acked on final message\n", call_to_destroy);
                  ast_mutex_lock(&iaxsl[call_to_destroy]);
                  iax2_destroy(call_to_destroy);
                  ast_mutex_unlock(&iaxsl[call_to_destroy]);
               }
            }
            /* Note how much we've received acknowledgement for */
            if (iaxs[fr->callno])
               iaxs[fr->callno]->rseqno = fr->iseqno;
            else {
               /* Stop processing now */
               ast_variables_destroy(ies.vars);
               ast_mutex_unlock(&iaxsl[fr->callno]);
               return 1;
            }
         } else {
            ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
         }
      }
      if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && 
         ((f.frametype != AST_FRAME_IAX) || 
          ((f.subclass != IAX_COMMAND_TXACC) &&
           (f.subclass != IAX_COMMAND_TXCNT)))) {
         /* Only messages we accept from a transfer host are TXACC and TXCNT */
         ast_variables_destroy(ies.vars);
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }

      /* when we receive the first full frame for a new incoming channel,
         it is safe to start the PBX on the channel because we have now
         completed a 3-way handshake with the peer */
      if ((f.frametype == AST_FRAME_VOICE) ||
          (f.frametype == AST_FRAME_VIDEO) ||
          (f.frametype == AST_FRAME_IAX)) {
         if (ast_test_flag(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
            ast_clear_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
            if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat)) {
               ast_variables_destroy(ies.vars);
               ast_mutex_unlock(&iaxsl[fr->callno]);
               return 1;
            }
         }

         if (ies.vars) {
            struct ast_datastore *variablestore = NULL;
            struct ast_variable *var, *prev = NULL;
            AST_LIST_HEAD(, ast_var_t) *varlist;

            iax2_lock_owner(fr->callno);
            if (!iaxs[fr->callno]) {
               ast_variables_destroy(ies.vars);
               ast_mutex_unlock(&iaxsl[fr->callno]);
               return 1;
            }
            if ((c = iaxs[fr->callno]->owner)) {
               varlist = ast_calloc(1, sizeof(*varlist));
               variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);

               if (variablestore && varlist) {
                  variablestore->data = varlist;
                  variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
                  AST_LIST_HEAD_INIT(varlist);
                  ast_debug(1, "I can haz IAX vars?\n");
                  for (var = ies.vars; var; var = var->next) {
                     struct ast_var_t *newvar = ast_var_assign(var->name, var->value);
                     if (prev) {
                        ast_free(prev);
                     }
                     prev = var;
                     if (!newvar) {
                        /* Don't abort list traversal, as this would leave ies.vars in an inconsistent state. */
                        ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                     } else {
                        AST_LIST_INSERT_TAIL(varlist, newvar, entries);
                     }
                  }
                  if (prev) {
                     ast_free(prev);
                  }
                  ies.vars = NULL;
                  ast_channel_datastore_add(c, variablestore);
               } else {
                  ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                  if (variablestore) {
                     ast_datastore_free(variablestore);
                  }
                  if (varlist) {
                     ast_free(varlist);
                  }
               }
               ast_channel_unlock(c);
            } else {
               /* No channel yet, so transfer the variables directly over to the pvt,
                * for later inheritance. */
               ast_debug(1, "No channel, so populating IAXVARs to the pvt, as an intermediate step.\n");
               for (var = ies.vars; var && var->next; var = var->next);
               if (var) {
                  var->next = iaxs[fr->callno]->iaxvars;
                  iaxs[fr->callno]->iaxvars = ies.vars;
                  ies.vars = NULL;
               }
            }
         }

         if (ies.vars) {
            ast_debug(1, "I have IAX variables, but they were not processed\n");
         }
      }

      /* once we receive our first IAX Full Frame that is not CallToken related, send all
       * queued signaling frames that were being held. */
      if ((f.frametype == AST_FRAME_IAX) && (f.subclass != IAX_COMMAND_CALLTOKEN) && iaxs[fr->callno]->hold_signaling) {
         send_signaling(iaxs[fr->callno]);
      }

      if (f.frametype == AST_FRAME_VOICE) {
         if (f.subclass != iaxs[fr->callno]->voiceformat) {
               iaxs[fr->callno]->voiceformat = f.subclass;
               ast_debug(1, "Ooh, voice format changed to %d\n", f.subclass);
               if (iaxs[fr->callno]->owner) {
                  iax2_lock_owner(fr->callno);
                  if (iaxs[fr->callno]) {
                     if (iaxs[fr->callno]->owner) {
                        int orignative;

                        orignative = iaxs[fr->callno]->owner->nativeformats;
                        iaxs[fr->callno]->owner->nativeformats = f.subclass;
                        if (iaxs[fr->callno]->owner->readformat)
                           ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);
                        iaxs[fr->callno]->owner->nativeformats = orignative;
                        ast_channel_unlock(iaxs[fr->callno]->owner);
                     }
                  } else {
                     ast_debug(1, "Neat, somebody took away the channel at a magical time but i found it!\n");
                     /* Free remote variables (if any) */
                     if (ies.vars) {
                        ast_variables_destroy(ies.vars);
                        ast_debug(1, "I can haz iaxvars, but they is no good.  :-(\n");
                        ies.vars = NULL;
                     }
                     ast_mutex_unlock(&iaxsl[fr->callno]);
                     return 1;
                  }
               }
         }
      }
      if (f.frametype == AST_FRAME_VIDEO) {
         if (f.subclass != iaxs[fr->callno]->videoformat) {
            ast_debug(1, "Ooh, video format changed to %d\n", f.subclass & ~0x1);
            iaxs[fr->callno]->videoformat = f.subclass & ~0x1;
         }
      }
      if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
         if (f.subclass == AST_CONTROL_BUSY) {
            iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_BUSY;
         } else if (f.subclass == AST_CONTROL_CONGESTION) {
            iaxs[fr->callno]->owner->hangupcause = AST_CAUSE_CONGESTION;
         }
      }
      if (f.frametype == AST_FRAME_IAX) {
         ast_sched_thread_del(sched, iaxs[fr->callno]->initid);
         /* Handle the IAX pseudo frame itself */
         if (iaxdebug)
            ast_debug(1, "IAX subclass %d received\n", f.subclass);

                        /* Update last ts unless the frame's timestamp originated with us. */
         if (iaxs[fr->callno]->last < fr->ts &&
                            f.subclass != IAX_COMMAND_ACK &&
                            f.subclass != IAX_COMMAND_PONG &&
                            f.subclass != IAX_COMMAND_LAGRP) {
            iaxs[fr->callno]->last = fr->ts;
            if (iaxdebug)
               ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
         }
         iaxs[fr->callno]->last_iax_message = f.subclass;
         if (!iaxs[fr->callno]->first_iax_message) {
            iaxs[fr->callno]->first_iax_message = f.subclass;
         }
         switch(f.subclass) {
         case IAX_COMMAND_ACK:
            /* Do nothing */
            break;
         case IAX_COMMAND_QUELCH:
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
                    /* Generate Manager Hold event, if necessary*/
               if (iaxs[fr->callno]->owner) {
                  manager_event(EVENT_FLAG_CALL, "Hold",
                     "Status: On\r\n"
                     "Channel: %s\r\n"
                     "Uniqueid: %s\r\n",
                     iaxs[fr->callno]->owner->name, 
                     iaxs[fr->callno]->owner->uniqueid);
               }

               ast_set_flag(iaxs[fr->callno], IAX_QUELCH);
               if (ies.musiconhold) {
                  iax2_lock_owner(fr->callno);
                  if (!iaxs[fr->callno] || !iaxs[fr->callno]->owner) {
                     break;
                  }
                  if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
                     const char *moh_suggest = iaxs[fr->callno]->mohsuggest;

                     /*
                      * We already hold the owner lock so we do not
                      * need to check iaxs[fr->callno] after it returns.
                      */
                     iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD, 
                        S_OR(moh_suggest, NULL),
                        !ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0);
                  }
                  ast_channel_unlock(iaxs[fr->callno]->owner);
               }
            }
            break;
         case IAX_COMMAND_UNQUELCH:
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
               iax2_lock_owner(fr->callno);
               if (!iaxs[fr->callno]) {
                  break;
               }
               /* Generate Manager Unhold event, if necessary */
               if (iaxs[fr->callno]->owner && ast_test_flag(iaxs[fr->callno], IAX_QUELCH)) {
                  manager_event(EVENT_FLAG_CALL, "Hold",
                     "Status: Off\r\n"
                     "Channel: %s\r\n"
                     "Uniqueid: %s\r\n",
                     iaxs[fr->callno]->owner->name, 
                     iaxs[fr->callno]->owner->uniqueid);
               }

               ast_clear_flag(iaxs[fr->callno], IAX_QUELCH);
               if (!iaxs[fr->callno]->owner) {
                  break;
               }
               if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
                  /*
                   * We already hold the owner lock so we do not
                   * need to check iaxs[fr->callno] after it returns.
                   */
                  iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
               }
               ast_channel_unlock(iaxs[fr->callno]->owner);
            }
            break;
         case IAX_COMMAND_TXACC:
            if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) {
               /* Ack the packet with the given timestamp */
               AST_LIST_LOCK(&frame_queue);
               AST_LIST_TRAVERSE(&frame_queue, cur, list) {
                  /* Cancel any outstanding txcnt's */
                  if ((fr->callno == cur->callno) && (cur->transfer))
                     cur->retries = -1;
               }
               AST_LIST_UNLOCK(&frame_queue);
               memset(&ied1, 0, sizeof(ied1));
               iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->callno);
               send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
               iaxs[fr->callno]->transferring = TRANSFER_READY;
            }
            break;
         case IAX_COMMAND_NEW:
            /* Ignore if it's already up */
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD))
               break;
            if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
               ast_mutex_unlock(&iaxsl[fr->callno]);
               check_provisioning(&sin, fd, ies.serviceident, ies.provver);
               ast_mutex_lock(&iaxsl[fr->callno]);
               if (!iaxs[fr->callno]) {
                  break;
               }
            }
            /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
            if (ast_test_flag(iaxs[fr->callno], IAX_TRUNK)) {
               int new_callno;
               if ((new_callno = make_trunk(fr->callno, 1)) != -1)
                  fr->callno = new_callno;
            }
            /* For security, always ack immediately */
            if (delayreject)
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            if (check_access(fr->callno, &sin, &ies)) {
               /* They're not allowed on */
               auth_fail(fr->callno, IAX_COMMAND_REJECT);
               if (authdebug)
                  ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
               break;
            }
            if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag(iaxs[fr->callno], IAX_FORCE_ENCRYPT)) {
               auth_fail(fr->callno, IAX_COMMAND_REJECT);
               ast_log(LOG_WARNING, "Rejected connect attempt.  No secret present while force encrypt enabled.\n");
               break;
            }
            if (strcasecmp(iaxs[fr->callno]->exten, "TBD")) {
               const char *context, *exten, *cid_num;

               context = ast_strdupa(iaxs[fr->callno]->context);
               exten = ast_strdupa(iaxs[fr->callno]->exten);
               cid_num = ast_strdupa(iaxs[fr->callno]->cid_num);

               /* This might re-enter the IAX code and need the lock */
               ast_mutex_unlock(&iaxsl[fr->callno]);
               exists = ast_exists_extension(NULL, context, exten, 1, cid_num);
               ast_mutex_lock(&iaxsl[fr->callno]);

               if (!iaxs[fr->callno]) {
                  break;
               }
            } else
               exists = 0;
            /* Get OSP token if it does exist */
            save_osptoken(fr, &ies);
            if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) {
               if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
                  memset(&ied0, 0, sizeof(ied0));
                  iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
                  iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
                  send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                  if (!iaxs[fr->callno]) {
                     break;
                  }
                  if (authdebug)
                     ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
               } else {
                  /* Select an appropriate format */

                  if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                     if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                        using_prefs = "reqonly";
                     } else {
                        using_prefs = "disabled";
                     }
                     format = iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability;
                     memset(&pref, 0, sizeof(pref));
                     strcpy(caller_pref_buf, "disabled");
                     strcpy(host_pref_buf, "disabled");
                  } else {
                     using_prefs = "mine";
                     /* If the information elements are in here... use them */
                     if (ies.codec_prefs)
                        ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
                     if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
                        /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
                        if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                           pref = iaxs[fr->callno]->rprefs;
                           using_prefs = "caller";
                        } else {
                           pref = iaxs[fr->callno]->prefs;
                        }
                     } else
                        pref = iaxs[fr->callno]->prefs;
                     
                     format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
                     ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
                     ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
                  }
                  if (!format) {
                     if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
                        format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
                     if (!format) {
                        memset(&ied0, 0, sizeof(ied0));
                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
                        send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                        if (!iaxs[fr->callno]) {
                           break;
                        }
                        if (authdebug) {
                           if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
                           else 
                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
                        }
                     } else {
                        /* Pick one... */
                        if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                           if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
                              format = 0;
                        } else {
                           if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                              using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
                              memset(&pref, 0, sizeof(pref));
                              format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                              strcpy(caller_pref_buf,"disabled");
                              strcpy(host_pref_buf,"disabled");
                           } else {
                              using_prefs = "mine";
                              if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
                                 /* Do the opposite of what we tried above. */
                                 if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                    pref = iaxs[fr->callno]->prefs;                       
                                 } else {
                                    pref = iaxs[fr->callno]->rprefs;
                                    using_prefs = "caller";
                                 }
                                 format = ast_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
                           
                              } else /* if no codec_prefs IE do it the old way */
                                 format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability); 
                           }
                        }

                        if (!format) {
                           memset(&ied0, 0, sizeof(ied0));
                           iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                           iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
                           ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                           send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                           if (!iaxs[fr->callno]) {
                              break;
                           }
                           if (authdebug)
                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
                           ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);   
                           break;
                        }
                     }
                  }
                  if (format) {
                     /* No authentication required, let them in */
                     memset(&ied1, 0, sizeof(ied1));
                     iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
                     send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
                     if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                        ast_verb(3, "Accepting UNAUTHENTICATED call from %s:\n"
                                    "%srequested format = %s,\n"
                                    "%srequested prefs = %s,\n"
                                    "%sactual format = %s,\n"
                                    "%shost prefs = %s,\n"
                                    "%spriority = %s\n",
                                    ast_inet_ntoa(sin.sin_addr), 
                                    VERBOSE_PREFIX_4,
                                    ast_getformatname(iaxs[fr->callno]->peerformat), 
                                    VERBOSE_PREFIX_4,
                                    caller_pref_buf,
                                    VERBOSE_PREFIX_4,
                                    ast_getformatname(format), 
                                    VERBOSE_PREFIX_4,
                                    host_pref_buf, 
                                    VERBOSE_PREFIX_4,
                                    using_prefs);
                        
                        iaxs[fr->callno]->chosenformat = format;
                        ast_set_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
                     } else {
                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
                        /* If this is a TBD call, we're ready but now what...  */
                        ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
                     }
                  }
               }
               break;
            }
            if (iaxs[fr->callno]->authmethods & IAX_AUTH_MD5)
               merge_encryption(iaxs[fr->callno],ies.encmethods);
            else
               iaxs[fr->callno]->encmethods = 0;
            if (!authenticate_request(fr->callno) && iaxs[fr->callno])
               ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED);
            break;
         case IAX_COMMAND_DPREQ:
            /* Request status in the dialplan */
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD) &&
               !ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED) && ies.called_number) {
               if (iaxcompat) {
                  /* Spawn a thread for the lookup */
                  spawn_dp_lookup(fr->callno, iaxs[fr->callno]->context, ies.called_number, iaxs[fr->callno]->cid_num);
               } else {
                  /* Just look it up */
                  dp_lookup(fr->callno, iaxs[fr->callno]->context, ies.called_number, iaxs[fr->callno]->cid_num, 1);
               }
            }
            break;
         case IAX_COMMAND_HANGUP:
            ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
            ast_debug(1, "Immediately destroying %d, having received hangup\n", fr->callno);
            /* Set hangup cause according to remote */
            if (ies.causecode && iaxs[fr->callno]->owner)
               iaxs[fr->callno]->owner->hangupcause = ies.causecode;
            /* Send ack immediately, before we destroy */
            send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            iax2_destroy(fr->callno);
            break;
         case IAX_COMMAND_REJECT:
            /* Set hangup cause according to remote */
            if (ies.causecode && iaxs[fr->callno]->owner)
               iaxs[fr->callno]->owner->hangupcause = ies.causecode;

            if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
               if (iaxs[fr->callno]->owner && authdebug)
                  ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
                     ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
                     ies.cause ? ies.cause : "<Unknown>");
               ast_debug(1, "Immediately destroying %d, having received reject\n",
                  fr->callno);
            }
            /* Send ack immediately, before we destroy */
            send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK,
                         fr->ts, NULL, 0, fr->iseqno);
            if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION))
               iaxs[fr->callno]->error = EPERM;
            iax2_destroy(fr->callno);
            break;
         case IAX_COMMAND_TRANSFER:
         {
            struct ast_channel *bridged_chan;
            struct ast_channel *owner;

            iax2_lock_owner(fr->callno);
            if (!iaxs[fr->callno]) {
               /* Initiating call went away before we could transfer. */
               break;
            }
            owner = iaxs[fr->callno]->owner;
            bridged_chan = owner ? ast_bridged_channel(owner) : NULL;
            if (bridged_chan && ies.called_number) {
               ast_mutex_unlock(&iaxsl[fr->callno]);

               /* Set BLINDTRANSFER channel variables */
               pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name);
               pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name);

               if (!strcmp(ies.called_number, ast_parking_ext())) {
                  ast_debug(1, "Parking call '%s'\n", bridged_chan->name);
                  if (iax_park(bridged_chan, owner)) {
                     ast_log(LOG_WARNING, "Failed to park call '%s'\n",
                        bridged_chan->name);
                  }
                  ast_mutex_lock(&iaxsl[fr->callno]);
               } else {
                  ast_mutex_lock(&iaxsl[fr->callno]);

                  if (iaxs[fr->callno]) {
                     if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context,
                        ies.called_number, 1)) {
                        ast_log(LOG_WARNING,
                           "Async goto of '%s' to '%s@%s' failed\n",
                           bridged_chan->name, ies.called_number,
                           iaxs[fr->callno]->context);
                     } else {
                        ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
                           bridged_chan->name, ies.called_number,
                           iaxs[fr->callno]->context);
                     }
                  } else {
                     /* Initiating call went away before we could transfer. */
                  }
               }
            } else {
               ast_debug(1, "Async goto not applicable on call %d\n", fr->callno);
            }
            if (owner) {
               ast_channel_unlock(owner);
            }

            break;
         }
         case IAX_COMMAND_ACCEPT:
            /* Ignore if call is already up or needs authentication or is a TBD */
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD | IAX_STATE_AUTHENTICATED))
               break;
            if (ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
               /* Send ack immediately, before we destroy */
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
               iax2_destroy(fr->callno);
               break;
            }
            if (ies.format) {
               iaxs[fr->callno]->peerformat = ies.format;
            } else {
               if (iaxs[fr->callno]->owner)
                  iaxs[fr->callno]->peerformat = iaxs[fr->callno]->owner->nativeformats;
               else
                  iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
            }
            ast_verb(3, "Call accepted by %s (format %s)\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), ast_getformatname(iaxs[fr->callno]->peerformat));
            if (!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability)) {
               memset(&ied0, 0, sizeof(ied0));
               iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
               iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
               if (!iaxs[fr->callno]) {
                  break;
               }
               if (authdebug)
                  ast_log(LOG_NOTICE, "Rejected call to %s, format 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
            } else {
               ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
               iax2_lock_owner(fr->callno);
               if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
                  /* Switch us to use a compatible format */
                  iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat;
                  ast_verb(3, "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats));

                  /* Setup read/write formats properly. */
                  if (iaxs[fr->callno]->owner->writeformat)
                     ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);   
                  if (iaxs[fr->callno]->owner->readformat)
                     ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);  
                  ast_channel_unlock(iaxs[fr->callno]->owner);
               }
            }
            if (iaxs[fr->callno]) {
               AST_LIST_LOCK(&dpcache);
               AST_LIST_TRAVERSE(&iaxs[fr->callno]->dpentries, dp, peer_list)
                  if (!(dp->flags & CACHE_FLAG_TRANSMITTED))
                     iax2_dprequest(dp, fr->callno);
               AST_LIST_UNLOCK(&dpcache);
            }
            break;
         case IAX_COMMAND_POKE:
            /* Send back a pong packet with the original timestamp */
            send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, NULL, 0, -1);
            break;
         case IAX_COMMAND_PING:
         {
            struct iax_ie_data pingied;
            construct_rr(iaxs[fr->callno], &pingied);
            /* Send back a pong packet with the original timestamp */
            send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, pingied.buf, pingied.pos, -1);
         }
            break;
         case IAX_COMMAND_PONG:
            /* Calculate ping time */
            iaxs[fr->callno]->pingtime =  calc_timestamp(iaxs[fr->callno], 0, &f) - fr->ts;
            /* save RR info */
            save_rr(fr, &ies);

            /* Good time to write jb stats for this call */
            log_jitterstats(fr->callno);

            if (iaxs[fr->callno]->peerpoke) {
               peer = iaxs[fr->callno]->peerpoke;
               if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) {
                  if (iaxs[fr->callno]->pingtime <= peer->maxms) {
                     ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
                     manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
                     ast_devstate_changed(AST_DEVICE_NOT_INUSE, "IAX2/%s", peer->name); /* Activate notification */
                  }
               } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                  if (iaxs[fr->callno]->pingtime > peer->maxms) {
                     ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
                     manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
                     ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
                  }
               }
               peer->lastms = iaxs[fr->callno]->pingtime;
               if (peer->smoothing && (peer->lastms > -1))
                  peer->historicms = (iaxs[fr->callno]->pingtime + peer->historicms) / 2;
               else if (peer->smoothing && peer->lastms < 0)
                  peer->historicms = (0 + peer->historicms) / 2;
               else              
                  peer->historicms = iaxs[fr->callno]->pingtime;

               /* Remove scheduled iax2_poke_noanswer */
               if (peer->pokeexpire > -1) {
                  if (!ast_sched_thread_del(sched, peer->pokeexpire)) {
                     peer_unref(peer);
                     peer->pokeexpire = -1;
                  }
               }
               /* Schedule the next cycle */
               if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) 
                  peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
               else
                  peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqok, iax2_poke_peer_s, peer_ref(peer));
               if (peer->pokeexpire == -1)
                  peer_unref(peer);
               /* and finally send the ack */
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
               /* And wrap up the qualify call */
               iax2_destroy(fr->callno);
               peer->callno = 0;
               ast_debug(1, "Peer %s: got pong, lastms %d, historicms %d, maxms %d\n", peer->name, peer->lastms, peer->historicms, peer->maxms);
            }
            break;
         case IAX_COMMAND_LAGRQ:
         case IAX_COMMAND_LAGRP:
            f.src = "LAGRQ";
            f.mallocd = 0;
            f.offset = 0;
            f.samples = 0;
            iax_frame_wrap(fr, &f);
            if(f.subclass == IAX_COMMAND_LAGRQ) {
               /* Received a LAGRQ - echo back a LAGRP */
               fr->af.subclass = IAX_COMMAND_LAGRP;
               iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
            } else {
               /* Received LAGRP in response to our LAGRQ */
               unsigned int ts;
               /* This is a reply we've been given, actually measure the difference */
               ts = calc_timestamp(iaxs[fr->callno], 0, &fr->af);
               iaxs[fr->callno]->lag = ts - fr->ts;
               if (iaxdebug)
                  ast_debug(1, "Peer %s lag measured as %dms\n",
                     ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->lag);
            }
            break;
         case IAX_COMMAND_AUTHREQ:
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
               ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
               break;
            }
            if (authenticate_reply(iaxs[fr->callno], &iaxs[fr->callno]->addr, &ies, iaxs[fr->callno]->secret, iaxs[fr->callno]->outkey)) {
               struct ast_frame hangup_fr = { .frametype = AST_FRAME_CONTROL,
                        .subclass = AST_CONTROL_HANGUP,
               };
               ast_log(LOG_WARNING, 
                  "I don't know how to authenticate %s to %s\n", 
                  ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
               iax2_queue_frame(fr->callno, &hangup_fr);
            }
            break;
         case IAX_COMMAND_AUTHREP:
            /* For security, always ack immediately */
            if (delayreject)
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            /* Ignore once we've started */
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
               ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
               break;
            }
            if (authenticate_verify(iaxs[fr->callno], &ies)) {
               if (authdebug)
                  ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->username);
               memset(&ied0, 0, sizeof(ied0));
               auth_fail(fr->callno, IAX_COMMAND_REJECT);
               break;
            }
            if (strcasecmp(iaxs[fr->callno]->exten, "TBD")) {
               /* This might re-enter the IAX code and need the lock */
               exists = ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num);
            } else
               exists = 0;
            if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
               if (authdebug)
                  ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
               memset(&ied0, 0, sizeof(ied0));
               iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
               iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
               if (!iaxs[fr->callno]) {
                  break;
               }
            } else {
               /* Select an appropriate format */
               if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                  if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                     using_prefs = "reqonly";
                  } else {
                     using_prefs = "disabled";
                  }
                  format = iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability;
                  memset(&pref, 0, sizeof(pref));
                  strcpy(caller_pref_buf, "disabled");
                  strcpy(host_pref_buf, "disabled");
               } else {
                  using_prefs = "mine";
                  if (ies.codec_prefs)
                     ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
                  if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
                     if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                        pref = iaxs[fr->callno]->rprefs;
                        using_prefs = "caller";
                     } else {
                        pref = iaxs[fr->callno]->prefs;
                     }
                  } else /* if no codec_prefs IE do it the old way */
                     pref = iaxs[fr->callno]->prefs;
               
                  format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
                  ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
                  ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
               }
               if (!format) {
                  if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                     ast_debug(1, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr->callno]->peerformat), iaxs[fr->callno]->peercapability);
                     format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
                  }
                  if (!format) {
                     if (authdebug) {
                        if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) 
                           ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
                        else
                           ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
                     }
                     memset(&ied0, 0, sizeof(ied0));
                     iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                     iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
                     send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                     if (!iaxs[fr->callno]) {
                        break;
                     }
                  } else {
                     /* Pick one... */
                     if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                        if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
                           format = 0;
                     } else {
                        if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                           using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
                           memset(&pref, 0, sizeof(pref));
                           format = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
                              iaxs[fr->callno]->peerformat : ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                           strcpy(caller_pref_buf,"disabled");
                           strcpy(host_pref_buf,"disabled");
                        } else {
                           using_prefs = "mine";
                           if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
                              /* Do the opposite of what we tried above. */
                              if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                 pref = iaxs[fr->callno]->prefs;                 
                              } else {
                                 pref = iaxs[fr->callno]->rprefs;
                                 using_prefs = "caller";
                              }
                              format = ast_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
                           } else /* if no codec_prefs IE do it the old way */
                              format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability); 
                        }
                     }
                     if (!format) {
                        ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                        if (authdebug) {
                           if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
                           else
                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
                        }
                        memset(&ied0, 0, sizeof(ied0));
                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
                        send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                        if (!iaxs[fr->callno]) {
                           break;
                        }
                     }
                  }
               }
               if (format) {
                  /* Authentication received */
                  memset(&ied1, 0, sizeof(ied1));
                  iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
                  send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
                  if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
                     ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                     ast_verb(3, "Accepting AUTHENTICATED call from %s:\n"
                                 "%srequested format = %s,\n"
                                 "%srequested prefs = %s,\n"
                                 "%sactual format = %s,\n"
                                 "%shost prefs = %s,\n"
                                 "%spriority = %s\n", 
                                 ast_inet_ntoa(sin.sin_addr), 
                                 VERBOSE_PREFIX_4,
                                 ast_getformatname(iaxs[fr->callno]->peerformat),
                                 VERBOSE_PREFIX_4,
                                 caller_pref_buf,
                                 VERBOSE_PREFIX_4,
                                 ast_getformatname(format),
                                 VERBOSE_PREFIX_4,
                                 host_pref_buf,
                                 VERBOSE_PREFIX_4,
                                 using_prefs);

                     ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                     if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format)))
                        iax2_destroy(fr->callno);
                     else if (ies.vars) {
                        struct ast_datastore *variablestore;
                        struct ast_variable *var, *prev = NULL;
                        AST_LIST_HEAD(, ast_var_t) *varlist;
                        varlist = ast_calloc(1, sizeof(*varlist));
                        variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
                        if (variablestore && varlist) {
                           variablestore->data = varlist;
                           variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
                           AST_LIST_HEAD_INIT(varlist);
                           ast_debug(1, "I can haz IAX vars? w00t\n");
                           for (var = ies.vars; var; var = var->next) {
                              struct ast_var_t *newvar = ast_var_assign(var->name, var->value);
                              if (prev)
                                 ast_free(prev);
                              prev = var;
                              if (!newvar) {
                                 /* Don't abort list traversal, as this would leave ies.vars in an inconsistent state. */
                                 ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                              } else {
                                 AST_LIST_INSERT_TAIL(varlist, newvar, entries);
                              }
                           }
                           if (prev)
                              ast_free(prev);
                           ies.vars = NULL;
                           ast_channel_datastore_add(c, variablestore);
                        } else {
                           ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                           if (variablestore)
                              ast_datastore_free(variablestore);
                           if (varlist)
                              ast_free(varlist);
                        }
                     }
                  } else {
                     ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
                     /* If this is a TBD call, we're ready but now what...  */
                     ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
                     if (ast_test_flag(iaxs[fr->callno], IAX_IMMEDIATE)) {
                        goto immediatedial;
                     }
                  }
               }
            }
            break;
         case IAX_COMMAND_DIAL:
immediatedial:
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD)) {
               ast_clear_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
               ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s");
               if (!ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num)) {
                  if (authdebug)
                     ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
                  memset(&ied0, 0, sizeof(ied0));
                  iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
                  iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
                  send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                  if (!iaxs[fr->callno]) {
                     break;
                  }
               } else {
                  ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                  ast_verb(3, "Accepting DIAL from %s, formats = 0x%x\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat);
                  ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                  send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
                  if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat)))
                     iax2_destroy(fr->callno);
                  else if (ies.vars) {
                     struct ast_datastore *variablestore;
                     struct ast_variable *var, *prev = NULL;
                     AST_LIST_HEAD(, ast_var_t) *varlist;
                     varlist = ast_calloc(1, sizeof(*varlist));
                     variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
                     ast_debug(1, "I can haz IAX vars? w00t\n");
                     if (variablestore && varlist) {
                        variablestore->data = varlist;
                        variablestore->inheritance = DATASTORE_INHERIT_FOREVER;
                        AST_LIST_HEAD_INIT(varlist);
                        for (var = ies.vars; var; var = var->next) {
                           struct ast_var_t *newvar = ast_var_assign(var->name, var->value);
                           if (prev)
                              ast_free(prev);
                           prev = var;
                           if (!newvar) {
                              /* Don't abort list traversal, as this would leave ies.vars in an inconsistent state. */
                              ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                           } else {
                              AST_LIST_INSERT_TAIL(varlist, newvar, entries);
                           }
                        }
                        if (prev)
                           ast_free(prev);
                        ies.vars = NULL;
                        ast_channel_datastore_add(c, variablestore);
                     } else {
                        ast_log(LOG_ERROR, "Memory allocation error while processing IAX2 variables\n");
                        if (variablestore)
                           ast_datastore_free(variablestore);
                        if (varlist)
                           ast_free(varlist);
                     }
                  }
               }
            }
            break;
         case IAX_COMMAND_INVAL:
            iaxs[fr->callno]->error = ENOTCONN;
            ast_debug(1, "Immediately destroying %d, having received INVAL\n", fr->callno);
            iax2_destroy(fr->callno);
            ast_debug(1, "Destroying call %d\n", fr->callno);
            break;
         case IAX_COMMAND_VNAK:
            ast_debug(1, "Received VNAK: resending outstanding frames\n");
            /* Force retransmission */
            vnak_retransmit(fr->callno, fr->iseqno);
            break;
         case IAX_COMMAND_REGREQ:
         case IAX_COMMAND_REGREL:
            /* For security, always ack immediately */
            if (delayreject)
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            if (register_verify(fr->callno, &sin, &ies)) {
               if (!iaxs[fr->callno]) {
                  break;
               }
               /* Send delayed failure */
               auth_fail(fr->callno, IAX_COMMAND_REGREJ);
               break;
            }
            if (!iaxs[fr->callno]) {
               break;
            }
            if ((ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) ||
                  ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) {

               if (f.subclass == IAX_COMMAND_REGREL)
                  memset(&sin, 0, sizeof(sin));
               if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh))
                  ast_log(LOG_WARNING, "Registry error\n");
               if (!iaxs[fr->callno]) {
                  break;
               }
               if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
                  ast_mutex_unlock(&iaxsl[fr->callno]);
                  check_provisioning(&sin, fd, ies.serviceident, ies.provver);
                  ast_mutex_lock(&iaxsl[fr->callno]);
               }
               break;
            }
            registry_authrequest(fr->callno);
            break;
         case IAX_COMMAND_REGACK:
            if (iax2_ack_registry(&ies, &sin, fr->callno)) 
               ast_log(LOG_WARNING, "Registration failure\n");
            /* Send ack immediately, before we destroy */
            send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            iax2_destroy(fr->callno);
            break;
         case IAX_COMMAND_REGREJ:
            if (iaxs[fr->callno]->reg) {
               if (authdebug) {
                  ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>", ast_inet_ntoa(sin.sin_addr));
                  manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nUsername: %s\r\nStatus: Rejected\r\nCause: %s\r\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>");
               }
               iaxs[fr->callno]->reg->regstate = REG_STATE_REJECTED;
            }
            /* Send ack immediately, before we destroy */
            send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            iax2_destroy(fr->callno);
            break;
         case IAX_COMMAND_REGAUTH:
            /* Authentication request */
            if (registry_rerequest(&ies, fr->callno, &sin)) {
               memset(&ied0, 0, sizeof(ied0));
               iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
               iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
            }
            break;
         case IAX_COMMAND_TXREJ:
            iaxs[fr->callno]->transferring = 0;
            ast_verb(3, "Channel '%s' unable to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
            memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
            if (iaxs[fr->callno]->bridgecallno) {
               if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
                  iaxs[iaxs[fr->callno]->bridgecallno]->transferring = 0;
                  send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
               }
            }
            break;
         case IAX_COMMAND_TXREADY:
            if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
                (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) {
               if (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)
                  iaxs[fr->callno]->transferring = TRANSFER_MREADY;
               else
                  iaxs[fr->callno]->transferring = TRANSFER_READY;
               ast_verb(3, "Channel '%s' ready to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
               if (iaxs[fr->callno]->bridgecallno) {
                  if ((iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_READY) ||
                      (iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_MREADY)) {
                     /* They're both ready, now release them. */
                     if (iaxs[fr->callno]->transferring == TRANSFER_MREADY) {
                        ast_verb(3, "Attempting media bridge of %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
                              iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");

                        iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA;
                        iaxs[fr->callno]->transferring = TRANSFER_MEDIA;

                        memset(&ied0, 0, sizeof(ied0));
                        memset(&ied1, 0, sizeof(ied1));
                        iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
                        iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
                        send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
                        send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
                     } else {
                        ast_verb(3, "Releasing %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>",
                              iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");

                        iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_RELEASED;
                        iaxs[fr->callno]->transferring = TRANSFER_RELEASED;
                        ast_set_flag(iaxs[iaxs[fr->callno]->bridgecallno], IAX_ALREADYGONE);
                        ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);

                        /* Stop doing lag & ping requests */
                        stop_stuff(fr->callno);
                        stop_stuff(iaxs[fr->callno]->bridgecallno);

                        memset(&ied0, 0, sizeof(ied0));
                        memset(&ied1, 0, sizeof(ied1));
                        iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno);
                        iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno);
                        send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1);
                        send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1);
                     }

                  }
               }
            }
            break;
         case IAX_COMMAND_TXREQ:
            try_transfer(iaxs[fr->callno], &ies);
            break;
         case IAX_COMMAND_TXCNT:
            if (iaxs[fr->callno]->transferring)
               send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
            break;
         case IAX_COMMAND_TXREL:
            /* Send ack immediately, rather than waiting until we've changed addresses */
            send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
            complete_transfer(fr->callno, &ies);
            stop_stuff(fr->callno); /* for attended transfer to work with libiax */
            break;   
         case IAX_COMMAND_TXMEDIA:
            if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
               AST_LIST_LOCK(&frame_queue);
               AST_LIST_TRAVERSE(&frame_queue, cur, list) {
                  /* Cancel any outstanding frames and start anew */
                  if ((fr->callno == cur->callno) && (cur->transfer))
                     cur->retries = -1;
               }
               AST_LIST_UNLOCK(&frame_queue);
               /* Start sending our media to the transfer address, but otherwise leave the call as-is */
               iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
            }
            break;
         case IAX_COMMAND_RTKEY:
            if (!IAX_CALLENCRYPTED(iaxs[fr->callno])) {
               ast_log(LOG_WARNING, 
                  "we've been told to rotate our encryption key, "
                  "but this isn't an encrypted call. bad things will happen.\n"
               );
               break;
            }

            IAX_DEBUGDIGEST("Receiving", ies.challenge);

            ast_aes_decrypt_key((unsigned char *) ies.challenge, &iaxs[fr->callno]->dcx);
            break;
         case IAX_COMMAND_DPREP:
            complete_dpreply(iaxs[fr->callno], &ies);
            break;
         case IAX_COMMAND_UNSUPPORT:
            ast_log(LOG_NOTICE, "Peer did not understand our iax command '%d'\n", ies.iax_unknown);
            break;
         case IAX_COMMAND_FWDOWNL:
            /* Firmware download */
            if (!ast_test_flag(&globalflags, IAX_ALLOWFWDOWNLOAD)) {
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, NULL, 0, -1);
               break;
            }
            memset(&ied0, 0, sizeof(ied0));
            res = iax_firmware_append(&ied0, (unsigned char *)ies.devicetype, ies.fwdesc);
            if (res < 0)
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
            else if (res > 0)
               send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
            else
               send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
            break;
         case IAX_COMMAND_CALLTOKEN:
         {
            struct iax_frame *cur;
            int found = 0;
            AST_LIST_LOCK(&frame_queue);
            AST_LIST_TRAVERSE(&frame_queue, cur, list) {
               /* find the last sent frame in our frame queue for this callno.
                * There are many things to take into account before resending this frame.
                * All of these are taken care of in resend_with_token() */
               if (cur->callno == fr->callno) {
                  found = 1;
                  break;
               }
            }
            AST_LIST_UNLOCK(&frame_queue);

            /* find last sent frame */
            if (cur && found && ies.calltoken && ies.calltokendata) {
               resend_with_token(fr->callno, cur, (char *) ies.calltokendata);
            }
            break;
         }
         default:
            ast_debug(1, "Unknown IAX command %d on %d/%d\n", f.subclass, fr->callno, iaxs[fr->callno]->peercallno);
            memset(&ied0, 0, sizeof(ied0));
            iax_ie_append_byte(&ied0, IAX_IE_IAX_UNKNOWN, f.subclass);
            send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, ied0.buf, ied0.pos, -1);
         }
         /* Free remote variables (if any) */
         if (ies.vars) {
            ast_variables_destroy(ies.vars);
            ast_debug(1, "I can haz IAX vars, but they is no good :-(\n");
            ies.vars = NULL;
         }

         /* Don't actually pass these frames along */
         if ((f.subclass != IAX_COMMAND_ACK) && 
           (f.subclass != IAX_COMMAND_TXCNT) && 
           (f.subclass != IAX_COMMAND_TXACC) && 
           (f.subclass != IAX_COMMAND_INVAL) &&
           (f.subclass != IAX_COMMAND_VNAK)) { 
            if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno)
               send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
         }
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }
      /* Unless this is an ACK or INVAL frame, ack it */
      if (iaxs[fr->callno] && iaxs[fr->callno]->aseqno != iaxs[fr->callno]->iseqno)
         send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
   } else if (minivid) {
      f.frametype = AST_FRAME_VIDEO;
      if (iaxs[fr->callno]->videoformat > 0) 
         f.subclass = iaxs[fr->callno]->videoformat | (ntohs(vh->ts) & 0x8000 ? 1 : 0);
      else {
         ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
         iax2_vnak(fr->callno);
         ast_variables_destroy(ies.vars);
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }
      f.datalen = res - sizeof(*vh);
      if (f.datalen)
         f.data.ptr = thread->buf + sizeof(*vh);
      else
         f.data.ptr = NULL;
#ifdef IAXTESTS
      if (test_resync) {
         fr->ts = (iaxs[fr->callno]->last & 0xFFFF8000L) | ((ntohs(vh->ts) + test_resync) & 0x7fff);
      } else
#endif /* IAXTESTS */
         fr->ts = (iaxs[fr->callno]->last & 0xFFFF8000L) | (ntohs(vh->ts) & 0x7fff);
   } else {
      /* A mini frame */
      f.frametype = AST_FRAME_VOICE;
      if (iaxs[fr->callno]->voiceformat > 0)
         f.subclass = iaxs[fr->callno]->voiceformat;
      else {
         ast_debug(1, "Received mini frame before first full voice frame\n");
         iax2_vnak(fr->callno);
         ast_variables_destroy(ies.vars);
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }
      f.datalen = res - sizeof(struct ast_iax2_mini_hdr);
      if (f.datalen < 0) {
         ast_log(LOG_WARNING, "Datalen < 0?\n");
         ast_variables_destroy(ies.vars);
         ast_mutex_unlock(&iaxsl[fr->callno]);
         return 1;
      }
      if (f.datalen)
         f.data.ptr = thread->buf + sizeof(*mh);
      else
         f.data.ptr = NULL;
#ifdef IAXTESTS
      if (test_resync) {
         fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | ((ntohs(mh->ts) + test_resync) & 0xffff);
      } else
#endif /* IAXTESTS */
      fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | ntohs(mh->ts);
      /* FIXME? Surely right here would be the right place to undo timestamp wraparound? */
   }
   /* Don't pass any packets until we're started */
   if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
      ast_variables_destroy(ies.vars);
      ast_mutex_unlock(&iaxsl[fr->callno]);
      return 1;
   }
   /* Common things */
   f.src = "IAX2";
   f.mallocd = 0;
   f.offset = 0;
   f.len = 0;
   if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
      f.samples = ast_codec_get_samples(&f);
      /* We need to byteswap incoming slinear samples from network byte order */
      if (f.subclass == AST_FORMAT_SLINEAR)
         ast_frame_byteswap_be(&f);
   } else
      f.samples = 0;
   iax_frame_wrap(fr, &f);

   /* If this is our most recent packet, use it as our basis for timestamping */
   if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
      /*iaxs[fr->callno]->last = fr->ts; (do it afterwards cos schedule/forward_delivery needs the last ts too)*/
      fr->outoforder = 0;
   } else {
      if (iaxdebug && iaxs[fr->callno])
         ast_debug(1, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr->ts, iaxs[fr->callno]->last);
      fr->outoforder = -1;
   }
   fr->cacheable = ((f.frametype == AST_FRAME_VOICE) || (f.frametype == AST_FRAME_VIDEO));
   duped_fr = iaxfrdup2(fr);
   if (duped_fr) {
      schedule_delivery(duped_fr, updatehistory, 0, &fr->ts);
   }
   if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts) {
      iaxs[fr->callno]->last = fr->ts;
#if 1
      if (iaxdebug)
         ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
#endif
   }

   /* Always run again */
   ast_variables_destroy(ies.vars);
   ast_mutex_unlock(&iaxsl[fr->callno]);
   return 1;
}
static int socket_process_meta ( int  packet_len,
struct ast_iax2_meta_hdr meta,
struct sockaddr_in *  sin,
int  sockfd,
struct iax_frame fr 
) [static]

Definition at line 9295 of file chan_iax2.c.

References ast_codec_get_samples(), AST_FRAME_VOICE, ast_inet_ntoa(), ast_log(), ast_mutex_unlock(), ast_test_flag, ast_tvnow(), ast_tvzero(), iax_frame::callno, ast_iax2_meta_trunk_entry::callno, ast_iax2_mini_hdr::callno, ast_iax2_meta_hdr::cmddata, ast_frame::data, ast_iax2_meta_trunk_hdr::data, ast_iax2_meta_hdr::data, ast_frame::datalen, find_callno_locked(), find_tpeer(), fix_peerts(), ast_frame::frametype, iax2_vnak(), IAX_FLAG_FULL, iax_frame_wrap(), IAX_META_TRUNK, IAX_META_TRUNK_MINI, IAX_META_TRUNK_SUPERMINI, IAX_STATE_STARTED, iaxfrdup2(), chan_iax2_pvt::last, ast_iax2_meta_trunk_entry::len, ast_iax2_meta_trunk_mini::len, len(), iax2_trunk_peer::lock, LOG_WARNING, ast_frame::mallocd, ast_iax2_meta_hdr::metacmd, ast_iax2_meta_trunk_mini::mini, NEW_PREVENT, ast_frame::offset, iax_frame::outoforder, ast_frame::ptr, iax2_trunk_peer::rxtrunktime, ast_frame::samples, schedule_delivery(), ast_frame::src, chan_iax2_pvt::state, ast_frame::subclass, iax2_trunk_peer::trunkact, iax_frame::ts, ast_iax2_mini_hdr::ts, ast_iax2_meta_trunk_hdr::ts, and chan_iax2_pvt::voiceformat.

Referenced by socket_process().

{
   unsigned char metatype;
   struct ast_iax2_meta_trunk_mini *mtm;
   struct ast_iax2_meta_trunk_hdr *mth;
   struct ast_iax2_meta_trunk_entry *mte;
   struct iax2_trunk_peer *tpeer;
   unsigned int ts;
   void *ptr;
   struct timeval rxtrunktime;
   struct ast_frame f = { 0, };

   if (packet_len < sizeof(*meta)) {
      ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", 
         ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
      return 1;
   }

   if (meta->metacmd != IAX_META_TRUNK)
      return 1;

   if (packet_len < (sizeof(*meta) + sizeof(*mth))) {
      ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %d min)\n", packet_len,
         (int) (sizeof(*meta) + sizeof(*mth)));
      return 1;
   }
   mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
   ts = ntohl(mth->ts);
   metatype = meta->cmddata;
   packet_len -= (sizeof(*meta) + sizeof(*mth));
   ptr = mth->data;
   tpeer = find_tpeer(sin, sockfd);
   if (!tpeer) {
      ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", 
         ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
      return 1;
   }
   tpeer->trunkact = ast_tvnow();
   if (!ts || ast_tvzero(tpeer->rxtrunktime))
      tpeer->rxtrunktime = tpeer->trunkact;
   rxtrunktime = tpeer->rxtrunktime;
   ast_mutex_unlock(&tpeer->lock);
   while (packet_len >= sizeof(*mte)) {
      /* Process channels */
      unsigned short callno, trunked_ts, len;

      if (metatype == IAX_META_TRUNK_MINI) {
         mtm = (struct ast_iax2_meta_trunk_mini *) ptr;
         ptr += sizeof(*mtm);
         packet_len -= sizeof(*mtm);
         len = ntohs(mtm->len);
         callno = ntohs(mtm->mini.callno);
         trunked_ts = ntohs(mtm->mini.ts);
      } else if (metatype == IAX_META_TRUNK_SUPERMINI) {
         mte = (struct ast_iax2_meta_trunk_entry *)ptr;
         ptr += sizeof(*mte);
         packet_len -= sizeof(*mte);
         len = ntohs(mte->len);
         callno = ntohs(mte->callno);
         trunked_ts = 0;
      } else {
         ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
         break;
      }
      /* Stop if we don't have enough data */
      if (len > packet_len)
         break;
      fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd, 0);
      if (!fr->callno)
         continue;

      /* If it's a valid call, deliver the contents.  If not, we
         drop it, since we don't have a scallno to use for an INVAL */
      /* Process as a mini frame */
      memset(&f, 0, sizeof(f));
      f.frametype = AST_FRAME_VOICE;
      if (!iaxs[fr->callno]) {
         /* drop it */
      } else if (iaxs[fr->callno]->voiceformat == 0) {
         ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
         iax2_vnak(fr->callno);
      } else {
         f.subclass = iaxs[fr->callno]->voiceformat;
         f.datalen = len;
         if (f.datalen >= 0) {
            if (f.datalen)
               f.data.ptr = ptr;
            else
               f.data.ptr = NULL;
            if (trunked_ts)
               fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
            else
               fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
            /* Don't pass any packets until we're started */
            if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
               struct iax_frame *duped_fr;

               /* Common things */
               f.src = "IAX2";
               f.mallocd = 0;
               f.offset = 0;
               if (f.datalen && (f.frametype == AST_FRAME_VOICE)) 
                  f.samples = ast_codec_get_samples(&f);
               else
                  f.samples = 0;
               fr->outoforder = 0;
               iax_frame_wrap(fr, &f);
               duped_fr = iaxfrdup2(fr);
               if (duped_fr)
                  schedule_delivery(duped_fr, 1, 1, &fr->ts);
               if (iaxs[fr->callno] && iaxs[fr->callno]->last < fr->ts)
                  iaxs[fr->callno]->last = fr->ts;
            }
         } else {
            ast_log(LOG_WARNING, "Datalen < 0?\n");
         }
      }
      ast_mutex_unlock(&iaxsl[fr->callno]);
      ptr += len;
      packet_len -= len;
   }

   return 1;
}
static int socket_read ( int *  id,
int  fd,
short  events,
void *  cbdata 
) [static]

Definition at line 9216 of file chan_iax2.c.

References ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_random(), iax2_thread::buf, iax2_thread::buf_len, iax2_thread::buf_size, iax2_thread::callno, iax2_thread::cond, ast_iax2_full_hdr::csub, iax2_thread::csub, iax2_thread::curfunc, defer_full_frame(), errno, iax2_thread::ffinfo, find_idle_thread(), handle_error(), IAX_FLAG_FULL, IAX_IOSTATE_IDLE, IAX_IOSTATE_READY, inaddrcmp(), iax2_thread::iofd, iax2_thread::iosin, iax2_thread::iostate, len(), iax2_thread::lock, LOG_WARNING, iax2_thread::readbuf, ast_iax2_full_hdr::scallno, signal_condition(), iax2_thread::sin, thread, ast_iax2_full_hdr::type, and iax2_thread::type.

Referenced by peer_set_srcaddr(), and set_config().

{
   struct iax2_thread *thread;
   socklen_t len;
   time_t t;
   static time_t last_errtime = 0;
   struct ast_iax2_full_hdr *fh;

   if (!(thread = find_idle_thread())) {
      time(&t);
      if (t != last_errtime)
         ast_debug(1, "Out of idle IAX2 threads for I/O, pausing!\n");
      last_errtime = t;
      usleep(1);
      return 1;
   }

   len = sizeof(thread->iosin);
   thread->iofd = fd;
   thread->buf_len = recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, (struct sockaddr *) &thread->iosin, &len);
   thread->buf_size = sizeof(thread->readbuf);
   thread->buf = thread->readbuf;
   if (thread->buf_len < 0) {
      if (errno != ECONNREFUSED && errno != EAGAIN)
         ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
      handle_error();
      thread->iostate = IAX_IOSTATE_IDLE;
      signal_condition(&thread->lock, &thread->cond);
      return 1;
   }
   if (test_losspct && ((100.0 * ast_random() / (RAND_MAX + 1.0)) < test_losspct)) { /* simulate random loss condition */
      thread->iostate = IAX_IOSTATE_IDLE;
      signal_condition(&thread->lock, &thread->cond);
      return 1;
   }
   
   /* Determine if this frame is a full frame; if so, and any thread is currently
      processing a full frame for the same callno from this peer, then drop this
      frame (and the peer will retransmit it) */
   fh = (struct ast_iax2_full_hdr *) thread->buf;
   if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
      struct iax2_thread *cur = NULL;
      uint16_t callno = ntohs(fh->scallno) & ~IAX_FLAG_FULL;
      
      AST_LIST_LOCK(&active_list);
      AST_LIST_TRAVERSE(&active_list, cur, list) {
         if ((cur->ffinfo.callno == callno) &&
             !inaddrcmp(&cur->ffinfo.sin, &thread->iosin))
            break;
      }
      if (cur) {
         /* we found another thread processing a full frame for this call,
            so queue it up for processing later. */
         defer_full_frame(thread, cur);
         AST_LIST_UNLOCK(&active_list);
         thread->iostate = IAX_IOSTATE_IDLE;
         signal_condition(&thread->lock, &thread->cond);
         return 1;
      } else {
         /* this thread is going to process this frame, so mark it */
         thread->ffinfo.callno = callno;
         memcpy(&thread->ffinfo.sin, &thread->iosin, sizeof(thread->ffinfo.sin));
         thread->ffinfo.type = fh->type;
         thread->ffinfo.csub = fh->csub;
         AST_LIST_INSERT_HEAD(&active_list, thread, list);
      }
      AST_LIST_UNLOCK(&active_list);
   }
   
   /* Mark as ready and send on its way */
   thread->iostate = IAX_IOSTATE_READY;
#ifdef DEBUG_SCHED_MULTITHREAD
   ast_copy_string(thread->curfunc, "socket_process", sizeof(thread->curfunc));
#endif
   signal_condition(&thread->lock, &thread->cond);

   return 1;
}
static void spawn_dp_lookup ( int  callno,
const char *  context,
const char *  callednum,
const char *  callerid 
) [static]

Definition at line 8932 of file chan_iax2.c.

References ast_calloc, ast_copy_string(), ast_log(), ast_pthread_create_detached, ast_strdup, dpreq_data::callednum, dpreq_data::callerid, dpreq_data::callno, dpreq_data::context, dp_lookup_thread(), and LOG_WARNING.

Referenced by socket_process().

{
   pthread_t newthread;
   struct dpreq_data *dpr;
   
   if (!(dpr = ast_calloc(1, sizeof(*dpr))))
      return;

   dpr->callno = callno;
   ast_copy_string(dpr->context, context, sizeof(dpr->context));
   ast_copy_string(dpr->callednum, callednum, sizeof(dpr->callednum));
   if (callerid)
      dpr->callerid = ast_strdup(callerid);
   if (ast_pthread_create_detached(&newthread, NULL, dp_lookup_thread, dpr)) {
      ast_log(LOG_WARNING, "Unable to start lookup thread!\n");
   }
}
static int start_network_thread ( void  ) [static]

Definition at line 11751 of file chan_iax2.c.

References ast_calloc, ast_cond_destroy(), ast_cond_init(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_pthread_create_background, ast_verb, iax2_thread::cond, iax2_process_thread(), IAX_THREAD_TYPE_POOL, iaxthreadcount, iax2_thread::init_cond, iax2_thread::init_lock, iax2_thread::lock, LOG_WARNING, network_thread(), thread, iax2_thread::threadid, iax2_thread::threadnum, and iax2_thread::type.

Referenced by load_module().

{
   struct iax2_thread *thread;
   int threadcount = 0;
   int x;
   for (x = 0; x < iaxthreadcount; x++) {
      thread = ast_calloc(1, sizeof(*thread));
      if (thread) {
         thread->type = IAX_THREAD_TYPE_POOL;
         thread->threadnum = ++threadcount;
         ast_mutex_init(&thread->lock);
         ast_cond_init(&thread->cond, NULL);
         ast_mutex_init(&thread->init_lock);
         ast_cond_init(&thread->init_cond, NULL);
         if (ast_pthread_create_background(&thread->threadid, NULL, iax2_process_thread, thread)) {
            ast_log(LOG_WARNING, "Failed to create new thread!\n");
            ast_mutex_destroy(&thread->lock);
            ast_cond_destroy(&thread->cond);
            ast_mutex_destroy(&thread->init_lock);
            ast_cond_destroy(&thread->init_cond);
            ast_free(thread);
            thread = NULL;
            continue;
         }
         AST_LIST_LOCK(&idle_list);
         AST_LIST_INSERT_TAIL(&idle_list, thread, list);
         AST_LIST_UNLOCK(&idle_list);
      }
   }
   ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
   ast_verb(2, "%d helper threads started\n", threadcount);
   return 0;
}
static void stop_stuff ( int  callno) [static]

Definition at line 8635 of file chan_iax2.c.

References iax2_destroy_helper().

Referenced by socket_process().

static void store_by_peercallno ( struct chan_iax2_pvt pvt) [static]

Definition at line 1999 of file chan_iax2.c.

References ao2_link, ast_log(), LOG_ERROR, and chan_iax2_pvt::peercallno.

Referenced by __find_callno(), complete_transfer(), and socket_process().

{
   if (!pvt->peercallno) {
      ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
      return;
   }

   ao2_link(iax_peercallno_pvts, pvt);
}
static void store_by_transfercallno ( struct chan_iax2_pvt pvt) [static]

Definition at line 1980 of file chan_iax2.c.

References ao2_link, ast_log(), LOG_ERROR, and chan_iax2_pvt::transfercallno.

Referenced by try_transfer().

{
   if (!pvt->transfercallno) {
      ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
      return;
   }

   ao2_link(iax_transfercallno_pvts, pvt);
}
static int timing_read ( int *  id,
int  fd,
short  events,
void *  cbdata 
) [static]

Definition at line 8821 of file chan_iax2.c.

References iax2_trunk_peer::addr, ast_debug, ast_free, ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_timer_ack(), ast_tvnow(), ast_verbose(), iax2_trunk_expired(), iax2_trunk_peer::lock, send_trunk(), totalcalls, iax2_trunk_peer::trunkdataalloc, and iax2_trunk_peer::trunkdatalen.

Referenced by network_thread().

{
   int res, processed = 0, totalcalls = 0;
   struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
   struct timeval now = ast_tvnow();

   if (iaxtrunkdebug)
      ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);

   if (timer) { 
      ast_timer_ack(timer, 1);
   }

   /* For each peer that supports trunking... */
   AST_LIST_LOCK(&tpeers);
   AST_LIST_TRAVERSE_SAFE_BEGIN(&tpeers, tpeer, list) {
      processed++;
      res = 0;
      ast_mutex_lock(&tpeer->lock);
      /* We can drop a single tpeer per pass.  That makes all this logic
         substantially easier */
      if (!drop && iax2_trunk_expired(tpeer, &now)) {
         /* Take it out of the list, but don't free it yet, because it
            could be in use */
         AST_LIST_REMOVE_CURRENT(list);
         drop = tpeer;
      } else {
         res = send_trunk(tpeer, &now);
         trunk_timed++; 
         if (iaxtrunkdebug)
            ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
      }     
      totalcalls += res;   
      res = 0;
      ast_mutex_unlock(&tpeer->lock);
   }
   AST_LIST_TRAVERSE_SAFE_END;
   AST_LIST_UNLOCK(&tpeers);

   if (drop) {
      ast_mutex_lock(&drop->lock);
      /* Once we have this lock, we're sure nobody else is using it or could use it once we release it, 
         because by the time they could get tpeerlock, we've already grabbed it */
      ast_debug(1, "Dropping unused iax2 trunk peer '%s:%d'\n", ast_inet_ntoa(drop->addr.sin_addr), ntohs(drop->addr.sin_port));
      if (drop->trunkdata) {
         ast_free(drop->trunkdata);
         drop->trunkdata = NULL;
      }
      ast_mutex_unlock(&drop->lock);
      ast_mutex_destroy(&drop->lock);
      ast_free(drop);
      
   }

   if (iaxtrunkdebug)
      ast_verbose("Ending trunk processing with %d peers and %d call chunks processed\n", processed, totalcalls);
   iaxtrunkdebug = 0;

   return 1;
}
static int transfercallno_pvt_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 13790 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, chan_iax2_pvt::frames_received, and match().

Referenced by load_objects().

{
   struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;

   /* The frames_received field is used to hold whether we're matching
    * against a full frame or not ... */

   return match(&pvt2->transfer, pvt2->transfercallno, pvt2->callno, pvt,
      pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
}
static int transfercallno_pvt_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 13783 of file chan_iax2.c.

References chan_iax2_pvt::transfercallno.

Referenced by load_objects().

{
   const struct chan_iax2_pvt *pvt = obj;

   return pvt->transfercallno;
}
static int transmit_trunk ( struct iax_frame f,
struct sockaddr_in *  sin,
int  sockfd 
) [static]

Definition at line 3164 of file chan_iax2.c.

References ast_debug, iax_frame::data, iax_frame::datalen, errno, and handle_error().

Referenced by send_trunk().

{
   int res;
   res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,
               sizeof(*sin));
   if (res < 0) {
      ast_debug(1, "Received error: %s\n", strerror(errno));
      handle_error();
   } else
      res = 0;
   return res;
}
static int try_firmware ( char *  s) [static]

Definition at line 2866 of file chan_iax2.c.

References ast_calloc, AST_FILE_MODE, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_random(), ast_strlen_zero(), buf, ast_iax2_firmware_header::chksum, ast_iax2_firmware_header::data, ast_iax2_firmware_header::datalen, iax_firmware::dead, ast_iax2_firmware_header::devname, errno, iax_firmware::fd, iax_firmware::fwh, IAX_FIRMWARE_MAGIC, last, len(), LOG_WARNING, ast_iax2_firmware_header::magic, MD5Final(), MD5Init(), MD5Update(), iax_firmware::mmaplen, s, and ast_iax2_firmware_header::version.

Referenced by reload_firmware().

{
   struct stat stbuf;
   struct iax_firmware *cur = NULL;
   int ifd, fd, res, len, chunk;
   struct ast_iax2_firmware_header *fwh, fwh2;
   struct MD5Context md5;
   unsigned char sum[16], buf[1024];
   char *s2, *last;

   if (!(s2 = alloca(strlen(s) + 100))) {
      ast_log(LOG_WARNING, "Alloca failed!\n");
      return -1;
   }

   last = strrchr(s, '/');
   if (last)
      last++;
   else
      last = s;

   snprintf(s2, strlen(s) + 100, "/var/tmp/%s-%ld", last, (unsigned long)ast_random());

   if ((res = stat(s, &stbuf) < 0)) {
      ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));
      return -1;
   }

   /* Make sure it's not a directory */
   if (S_ISDIR(stbuf.st_mode))
      return -1;
   ifd = open(s, O_RDONLY);
   if (ifd < 0) {
      ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));
      return -1;
   }
   fd = open(s2, O_RDWR | O_CREAT | O_EXCL, AST_FILE_MODE);
   if (fd < 0) {
      ast_log(LOG_WARNING, "Cannot open '%s' for writing: %s\n", s2, strerror(errno));
      close(ifd);
      return -1;
   }
   /* Unlink our newly created file */
   unlink(s2);
   
   /* Now copy the firmware into it */
   len = stbuf.st_size;
   while(len) {
      chunk = len;
      if (chunk > sizeof(buf))
         chunk = sizeof(buf);
      res = read(ifd, buf, chunk);
      if (res != chunk) {
         ast_log(LOG_WARNING, "Only read %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
         close(ifd);
         close(fd);
         return -1;
      }
      res = write(fd, buf, chunk);
      if (res != chunk) {
         ast_log(LOG_WARNING, "Only write %d of %d bytes of data :(: %s\n", res, chunk, strerror(errno));
         close(ifd);
         close(fd);
         return -1;
      }
      len -= chunk;
   }
   close(ifd);
   /* Return to the beginning */
   lseek(fd, 0, SEEK_SET);
   if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {
      ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);
      close(fd);
      return -1;
   }
   if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {
      ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);
      close(fd);
      return -1;
   }
   if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {
      ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);
      close(fd);
      return -1;
   }
   if (fwh2.devname[sizeof(fwh2.devname) - 1] || ast_strlen_zero((char *)fwh2.devname)) {
      ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
      close(fd);
      return -1;
   }
   fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 
   if (fwh == (void *) -1) {
      ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
      close(fd);
      return -1;
   }
   MD5Init(&md5);
   MD5Update(&md5, fwh->data, ntohl(fwh->datalen));
   MD5Final(sum, &md5);
   if (memcmp(sum, fwh->chksum, sizeof(sum))) {
      ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);
      munmap((void*)fwh, stbuf.st_size);
      close(fd);
      return -1;
   }

   AST_LIST_TRAVERSE(&firmwares, cur, list) {
      if (!strcmp((char *)cur->fwh->devname, (char *)fwh->devname)) {
         /* Found a candidate */
         if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
            /* The version we have on loaded is older, load this one instead */
            break;
         /* This version is no newer than what we have.  Don't worry about it.
            We'll consider it a proper load anyhow though */
         munmap((void*)fwh, stbuf.st_size);
         close(fd);
         return 0;
      }
   }
   
   if (!cur && ((cur = ast_calloc(1, sizeof(*cur))))) {
      cur->fd = -1;
      AST_LIST_INSERT_TAIL(&firmwares, cur, list);
   }
   
   if (cur) {
      if (cur->fwh)
         munmap((void*)cur->fwh, cur->mmaplen);
      if (cur->fd > -1)
         close(cur->fd);
      cur->fwh = fwh;
      cur->fd = fd;
      cur->mmaplen = stbuf.st_size;
      cur->dead = 0;
   }
   
   return 0;
}
static int try_transfer ( struct chan_iax2_pvt pvt,
struct iax_ies ies 
) [static]

Definition at line 7978 of file chan_iax2.c.

References iax_ies::apparent_addr, AST_FRAME_IAX, ast_log(), iax_ie_data::buf, iax_ies::callno, IAX_COMMAND_TXCNT, iax_ie_append_int(), IAX_IE_TRANSFERID, inet_aton(), LOG_WARNING, iax_ie_data::pos, send_command_transfer(), store_by_transfercallno(), chan_iax2_pvt::transfer, TRANSFER_BEGIN, TRANSFER_NONE, chan_iax2_pvt::transfercallno, iax_ies::transferid, chan_iax2_pvt::transferid, and chan_iax2_pvt::transferring.

Referenced by socket_process().

{
   int newcall = 0;
   char newip[256];
   struct iax_ie_data ied;
   struct sockaddr_in new;
   
   
   memset(&ied, 0, sizeof(ied));
   if (ies->apparent_addr)
      memmove(&new, ies->apparent_addr, sizeof(new));
   if (ies->callno)
      newcall = ies->callno;
   if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
      ast_log(LOG_WARNING, "Invalid transfer request\n");
      return -1;
   }
   pvt->transfercallno = newcall;
   memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
   inet_aton(newip, &pvt->transfer.sin_addr);
   pvt->transfer.sin_family = AF_INET;
   pvt->transferid = ies->transferid;
   /* only store by transfercallno if this is a new transfer,
    * just in case we get a duplicate TXREQ */
   if (pvt->transferring == TRANSFER_NONE) {
      store_by_transfercallno(pvt);
   }
   pvt->transferring = TRANSFER_BEGIN;

   if (ies->transferid)
      iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
   send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
   return 0;
}
static int uncompress_subclass ( unsigned char  csub) [static]

Definition at line 1521 of file chan_iax2.c.

References iax2_thread::csub, IAX_FLAG_SC_LOG, and IAX_MAX_SHIFT.

Referenced by decode_frame(), handle_call_token(), and socket_process().

{
   /* If the SC_LOG flag is set, return 2^csub otherwise csub */
   if (csub & IAX_FLAG_SC_LOG) {
      /* special case for 'compressed' -1 */
      if (csub == 0xff)
         return -1;
      else
         return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
   }
   else
      return csub;
}
static void unlink_peer ( struct iax2_peer peer) [static]

Definition at line 8269 of file chan_iax2.c.

References ao2_unlink, ast_sched_thread_del, iax2_peer::expire, peer_unref(), and iax2_peer::pokeexpire.

Referenced by __expire_registry(), build_peer(), and prune_peers().

{
   if (peer->expire > -1) {
      if (!ast_sched_thread_del(sched, peer->expire)) {
         peer->expire = -1;
         peer_unref(peer);
      }
   }

   if (peer->pokeexpire > -1) {
      if (!ast_sched_thread_del(sched, peer->pokeexpire)) {
         peer->pokeexpire = -1;
         peer_unref(peer);
      }
   }

   ao2_unlink(peers, peer);
}
static int unload_module ( void  ) [static]
static void unlock_both ( unsigned short  callno0,
unsigned short  callno1 
) [static]

Definition at line 5197 of file chan_iax2.c.

References ast_mutex_unlock().

Referenced by iax2_bridge().

{
   ast_mutex_unlock(&iaxsl[callno1]);
   ast_mutex_unlock(&iaxsl[callno0]);
}
static void unwrap_timestamp ( struct iax_frame fr) [static]

Definition at line 3849 of file chan_iax2.c.

References iax_frame::af, ast_debug, AST_FRAME_VIDEO, iax_frame::callno, ast_frame::frametype, chan_iax2_pvt::last, and iax_frame::ts.

Referenced by schedule_delivery().

{
   /* Video mini frames only encode the lower 15 bits of the session
    * timestamp, but other frame types (e.g. audio) encode 16 bits. */
   const int ts_shift = (fr->af.frametype == AST_FRAME_VIDEO) ? 15 : 16;
   const int lower_mask = (1 << ts_shift) - 1;
   const int upper_mask = ~lower_mask;
   const int last_upper = iaxs[fr->callno]->last & upper_mask;

   if ( (fr->ts & upper_mask) == last_upper ) {
      const int x = fr->ts - iaxs[fr->callno]->last;
      const int threshold = (ts_shift == 15) ? 25000 : 50000;

      if (x < -threshold) {
         /* Sudden big jump backwards in timestamp:
            What likely happened here is that miniframe timestamp has circled but we haven't
            gotten the update from the main packet.  We'll just pretend that we did, and
            update the timestamp appropriately. */
         fr->ts = (last_upper + (1 << ts_shift)) | (fr->ts & lower_mask);
         if (iaxdebug)
            ast_debug(1, "schedule_delivery: pushed forward timestamp\n");
      } else if (x > threshold) {
         /* Sudden apparent big jump forwards in timestamp:
            What's likely happened is this is an old miniframe belonging to the previous
            top 15 or 16-bit timestamp that has turned up out of order.
            Adjust the timestamp appropriately. */
         fr->ts = (last_upper - (1 << ts_shift)) | (fr->ts & lower_mask);
         if (iaxdebug)
            ast_debug(1, "schedule_delivery: pushed back timestamp\n");
      }
   }
}
static void update_jbsched ( struct chan_iax2_pvt pvt) [static]

Definition at line 3884 of file chan_iax2.c.

References ast_tvdiff_ms(), ast_tvnow(), chan_iax2_pvt::callno, CALLNO_TO_PTR, get_from_jb(), iax2_sched_replace(), chan_iax2_pvt::jb, jb_next(), chan_iax2_pvt::jbid, and chan_iax2_pvt::rxcore.

Referenced by __get_from_jb(), and schedule_delivery().

{
   int when;
   
   when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
   
   when = jb_next(pvt->jb) - when;

   if (when <= 0) {
      /* XXX should really just empty until when > 0.. */
      when = 1;
   }
   
   pvt->jbid = iax2_sched_replace(pvt->jbid, sched, when, get_from_jb, 
      CALLNO_TO_PTR(pvt->callno));
}
static void update_max_nontrunk ( void  ) [static]

Definition at line 1908 of file chan_iax2.c.

References ast_debug, and TRUNK_CALL_START.

Referenced by __find_callno(), and make_trunk().

{
   int max = 1;
   int x;
   /* XXX Prolly don't need locks here XXX */
   for (x=1;x<TRUNK_CALL_START - 1; x++) {
      if (iaxs[x])
         max = x + 1;
   }
   maxnontrunkcall = max;
   if (iaxdebug)
      ast_debug(1, "New max nontrunk callno is %d\n", max);
}
static void update_max_trunk ( void  ) [static]

Definition at line 1891 of file chan_iax2.c.

References ARRAY_LEN, ast_debug, and TRUNK_CALL_START.

Referenced by iax2_destroy(), and make_trunk().

{
   int max = TRUNK_CALL_START;
   int x;

   /* XXX Prolly don't need locks here XXX */
   for (x = TRUNK_CALL_START; x < ARRAY_LEN(iaxs) - 1; x++) {
      if (iaxs[x]) {
         max = x + 1;
      }
   }

   maxtrunkcall = max;
   if (iaxdebug)
      ast_debug(1, "New max trunk callno is %d\n", max);
}
static int update_packet ( struct iax_frame f) [static]

Definition at line 3302 of file chan_iax2.c.

References build_rand_pad(), iax_frame::callno, iax_frame::data, iax_frame::datalen, iax_frame::dcallno, ast_iax2_full_hdr::dcallno, decode_frame(), iax_frame::ecx, iax_frame::encmethods, encrypt_frame(), IAX_FLAG_RETRANS, ast_iax2_full_hdr::iseqno, chan_iax2_pvt::iseqno, iax_frame::iseqno, iax_frame::mydcx, and iax_frame::semirand.

Referenced by __attempt_transmit().

{
   /* Called with iaxsl lock held, and iaxs[callno] non-NULL */
   struct ast_iax2_full_hdr *fh = f->data;
   struct ast_frame af;

   /* if frame is encrypted. decrypt before updating it. */
   if (f->encmethods) {
      decode_frame(&f->mydcx, fh, &af, &f->datalen);
   }
   /* Mark this as a retransmission */
   fh->dcallno = ntohs(IAX_FLAG_RETRANS | f->dcallno);
   /* Update iseqno */
   f->iseqno = iaxs[f->callno]->iseqno;
   fh->iseqno = f->iseqno;

   /* Now re-encrypt the frame */
   if (f->encmethods) {
   /* since this is a retransmit frame, create a new random padding
    * before re-encrypting. */
      build_rand_pad(f->semirand, sizeof(f->semirand));
      encrypt_frame(&f->ecx, fh, f->semirand, &f->datalen);
   }
   return 0;
}
static int update_registry ( struct sockaddr_in *  sin,
int  callno,
char *  devtype,
int  fd,
unsigned short  refresh 
) [static]
Precondition:
iaxsl[callno] is locked
Note:
Since this function calls send_command_final(), the pvt struct for the given call number may disappear while executing this function.

Definition at line 8380 of file chan_iax2.c.

References iax2_peer::addr, ast_app_inboxcount(), ast_db_del(), ast_db_put(), AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_devstate_changed(), ast_event_destroy(), ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, AST_FRAME_IAX, ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_thread_del, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, iax_ie_data::buf, iax2_peer::cid_name, iax2_peer::cid_num, context, EVENT_FLAG_SYSTEM, iax2_peer::expire, expire_registry(), iax2_peer::expiry, find_peer(), iax2_datetime(), iax2_poke_peer(), iax2_regfunk, iax2_sched_add(), iax_check_version(), IAX_COMMAND_REGACK, IAX_HASCALLERID, IAX_IE_APPARENT_ADDR, iax_ie_append_addr(), iax_ie_append_int(), iax_ie_append_short(), iax_ie_append_str(), IAX_IE_CALLING_NAME, IAX_IE_CALLING_NUMBER, IAX_IE_DATETIME, IAX_IE_FIRMWAREVER, IAX_IE_MSGCOUNT, IAX_IE_REFRESH, IAX_IE_USERNAME, IAX_RTCACHEFRIENDS, IAX_RTUPDATE, IAX_STATE_AUTHENTICATED, IAX_TEMPONLY, inaddrcmp(), LOG_NOTICE, LOG_WARNING, mailbox, iax2_peer::mailbox, manager_event, max_reg_expire, iax2_peer::maxcallno, min_reg_expire, iax2_peer::name, peer_ref(), peer_unref(), peercnt_modify(), iax_ie_data::pos, realtime_update_peer(), register_peer_exten(), send_command_final(), iax2_peer::sockfd, strsep(), version, and iax2_peer::zonetag.

Referenced by socket_process().

{
   /* Called from IAX thread only, with proper iaxsl lock */
   struct iax_ie_data ied;
   struct iax2_peer *p;
   int msgcount;
   char data[80];
   int version;
   const char *peer_name;
   int res = -1;

   memset(&ied, 0, sizeof(ied));

   peer_name = ast_strdupa(iaxs[callno]->peer);

   /* SLD: Another find_peer call during registration - this time when we are really updating our registration */
   ast_mutex_unlock(&iaxsl[callno]);
   if (!(p = find_peer(peer_name, 1))) {
      ast_mutex_lock(&iaxsl[callno]);
      ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
      return -1;
   }
   ast_mutex_lock(&iaxsl[callno]);
   if (!iaxs[callno])
      goto return_unref;

   if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
      if (sin->sin_addr.s_addr) {
         time_t nowtime;
         time(&nowtime);
         realtime_update_peer(peer_name, sin, nowtime);
      } else {
         realtime_update_peer(peer_name, sin, 0);
      }
   }
   if (inaddrcmp(&p->addr, sin)) {
      if (iax2_regfunk)
         iax2_regfunk(p->name, 1);

      /* modify entry in peercnts table as _not_ registered */
      peercnt_modify(0, 0, &p->addr);

      /* Stash the IP address from which they registered */
      memcpy(&p->addr, sin, sizeof(p->addr));

      snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
      if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
         ast_db_put("IAX/Registry", p->name, data);
         ast_verb(3, "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
                   ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
         manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
         register_peer_exten(p, 1);
         ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
      } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
         ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
                   ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
         manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
         register_peer_exten(p, 0);
         ast_db_del("IAX/Registry", p->name);
         ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", p->name); /* Activate notification */
      }
      /* Update the host */
      /* Verify that the host is really there */
      iax2_poke_peer(p, callno);
   }

   /* modify entry in peercnts table as registered */
   if (p->maxcallno) {
      peercnt_modify(1, p->maxcallno, &p->addr);
   }

   /* Make sure our call still exists, an INVAL at the right point may make it go away */
   if (!iaxs[callno]) {
      res = -1;
      goto return_unref;
   }

   /* Store socket fd */
   p->sockfd = fd;
   /* Setup the expiry */
   if (p->expire > -1) {
      if (!ast_sched_thread_del(sched, p->expire)) {
         p->expire = -1;
         peer_unref(p);
      }
   }
   /* treat an unspecified refresh interval as the minimum */
   if (!refresh)
      refresh = min_reg_expire;
   if (refresh > max_reg_expire) {
      ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
         p->name, max_reg_expire, refresh);
      p->expiry = max_reg_expire;
   } else if (refresh < min_reg_expire) {
      ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
         p->name, min_reg_expire, refresh);
      p->expiry = min_reg_expire;
   } else {
      p->expiry = refresh;
   }
   if (p->expiry && sin->sin_addr.s_addr) {
      p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
      if (p->expire == -1)
         peer_unref(p);
   }
   iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
   iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
   if (sin->sin_addr.s_addr) {
      iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
      iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &p->addr);
      if (!ast_strlen_zero(p->mailbox)) {
         struct ast_event *event;
         int new, old;
         char *mailbox, *context;

         context = mailbox = ast_strdupa(p->mailbox);
         strsep(&context, "@");
         if (ast_strlen_zero(context))
            context = "default";

         event = ast_event_get_cached(AST_EVENT_MWI,
            AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
            AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
            AST_EVENT_IE_END);
         if (event) {
            new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
            old = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS);
            ast_event_destroy(event);
         } else { /* Fall back on checking the mailbox directly */
            ast_app_inboxcount(p->mailbox, &new, &old);
         }

         if (new > 255) {
            new = 255;
         }
         if (old > 255) {
            old = 255;
         }
         msgcount = (old << 8) | new;

         iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
      }
      if (ast_test_flag(p, IAX_HASCALLERID)) {
         iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
         iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
      }
   }
   version = iax_check_version(devtype);
   if (version) 
      iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);

   res = 0;

return_unref:
   peer_unref(p);

   return res ? res : send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
}
static int user_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]
Note:
The only member of the user passed here guaranteed to be set is the name field

Definition at line 1568 of file chan_iax2.c.

References CMP_MATCH, CMP_STOP, and iax2_user::name.

Referenced by load_objects().

{
   struct iax2_user *user = obj, *user2 = arg;

   return !strcmp(user->name, user2->name) ? CMP_MATCH | CMP_STOP : 0;
}
static int user_delme_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 12458 of file chan_iax2.c.

References ast_set_flag, and IAX_DELME.

Referenced by delete_users().

{
   struct iax2_user *user = obj;

   ast_set_flag(user, IAX_DELME);

   return 0;
}
static void user_destructor ( void *  obj) [static]
static int user_hash_cb ( const void *  obj,
const int  flags 
) [static]
Note:
The only member of the user passed here guaranteed to be set is the name field

Definition at line 1558 of file chan_iax2.c.

References ast_str_hash(), and iax2_user::name.

Referenced by load_objects().

{
   const struct iax2_user *user = obj;

   return ast_str_hash(user->name);
}
static struct iax2_user* user_ref ( struct iax2_user user) [static, read]

Definition at line 1615 of file chan_iax2.c.

References ao2_ref, and user.

{
   ao2_ref(user, +1);
   return user;
}
static void vnak_retransmit ( int  callno,
int  last 
) [static]

Definition at line 8736 of file chan_iax2.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, iax_frame::callno, f, iax_frame::oseqno, iax_frame::retries, and send_packet().

Referenced by socket_process().

{
   struct iax_frame *f;

   AST_LIST_LOCK(&frame_queue);
   AST_LIST_TRAVERSE(&frame_queue, f, list) {
      /* Send a copy immediately */
      if ((f->callno == callno) && iaxs[f->callno] &&
         ((unsigned char ) (f->oseqno - last) < 128) &&
         (f->retries >= 0)) {
         send_packet(f);
      }
   }
   AST_LIST_UNLOCK(&frame_queue);
}
static int wait_for_peercallno ( struct chan_iax2_pvt pvt) [static]
Note:
expects the pvt to be locked

Definition at line 5051 of file chan_iax2.c.

References chan_iax2_pvt::callno, DEADLOCK_AVOIDANCE, and chan_iax2_pvt::peercallno.

Referenced by iax2_indicate(), and iax2_setoption().

{
   unsigned short callno = pvt->callno;

   if (!pvt->peercallno) {
      /* We don't know the remote side's call number, yet.  :( */
      int count = 10;
      while (count-- && pvt && !pvt->peercallno) {
         DEADLOCK_AVOIDANCE(&iaxsl[callno]);
         pvt = iaxs[callno];
      }
      if (!pvt->peercallno) {
         return -1;
      }
   }

   return 0;
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Inter Asterisk eXchange (Ver 2)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 13972 of file chan_iax2.c.

struct active_list active_list [static]
int adsi = 0 [static]

Definition at line 332 of file chan_iax2.c.

Referenced by build_peer(), and build_user().

int amaflags = 0 [static]

Definition at line 331 of file chan_iax2.c.

Referenced by __find_callno().

Definition at line 13972 of file chan_iax2.c.

int authdebug = 1 [static]

Definition at line 242 of file chan_iax2.c.

int autokill = 0 [static]

Definition at line 243 of file chan_iax2.c.

struct ao2_container* callno_limits [static]

Table containing custom callno limit rules for a range of ip addresses.

Definition at line 837 of file chan_iax2.c.

struct ao2_container* callno_pool [static]

table of available call numbers

Definition at line 796 of file chan_iax2.c.

const unsigned int CALLNO_POOL_BUCKETS = 2699 [static]

Definition at line 801 of file chan_iax2.c.

struct ao2_container* callno_pool_trunk [static]

table of available trunk call numbers

Definition at line 799 of file chan_iax2.c.

struct ao2_container* calltoken_ignores [static]

Table containing ip addresses not requiring calltoken validation

Definition at line 840 of file chan_iax2.c.

struct ast_cli_entry cli_iax2[] [static]

Definition at line 13636 of file chan_iax2.c.

unsigned int cos

Definition at line 253 of file chan_iax2.c.

struct sockaddr_in debugaddr [static]

Definition at line 1044 of file chan_iax2.c.

Referenced by handle_cli_iax2_set_debug(), iax_outputframe(), and reload_config().

uint16_t DEFAULT_MAXCALLNO_LIMIT = 2048 [static]

Definition at line 842 of file chan_iax2.c.

Referenced by set_config().

uint16_t DEFAULT_MAXCALLNO_LIMIT_NONVAL = 8192 [static]

Definition at line 844 of file chan_iax2.c.

Referenced by set_config().

char default_parkinglot[AST_MAX_CONTEXT] [static]

Definition at line 223 of file chan_iax2.c.

int defaultsockfd = -1 [static]

Definition at line 265 of file chan_iax2.c.

Referenced by build_peer(), create_addr(), peer_set_sock_cb(), and peer_set_srcaddr().

int delayreject = 0 [static]

Definition at line 333 of file chan_iax2.c.

struct dpcache dpcache [static]
struct dynamic_list dynamic_list [static]
struct firmwares firmwares [static]
struct frame_queue frame_queue [static]
int global_max_trunk_mtu [static]

Maximum MTU, 0 if not used

Definition at line 218 of file chan_iax2.c.

uint16_t global_maxcallno [static]

Definition at line 846 of file chan_iax2.c.

Referenced by set_peercnt_limit().

uint16_t global_maxcallno_nonval [static]

Total num of call numbers allowed to be allocated without calltoken validation

Definition at line 849 of file chan_iax2.c.

int global_rtautoclear = 120 [static]

Definition at line 386 of file chan_iax2.c.

struct ast_flags globalflags = { 0 } [static]

Definition at line 336 of file chan_iax2.c.

int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH [static]

Definition at line 314 of file chan_iax2.c.

Referenced by build_peer(), build_user(), iax2_request(), and set_config().

int iax2_encryption = 0 [static]

Definition at line 334 of file chan_iax2.c.

Referenced by build_peer(), build_user(), and iax2_call().

int(* iax2_regfunk)(const char *username, int onoff) = NULL

Definition at line 267 of file chan_iax2.c.

Referenced by __expire_registry(), reg_source_db(), and update_registry().

struct ast_switch iax2_switch [static]

Definition at line 13522 of file chan_iax2.c.

struct ast_channel_tech iax2_tech [static]

Definition at line 1158 of file chan_iax2.c.

Referenced by ast_iax2_new().

Initial value:
 {
   .type = "IAX2_VARIABLE",
   .duplicate = iax2_dup_variable_datastore,
   .destroy = iax2_free_variable_datastore,
}

Definition at line 1235 of file chan_iax2.c.

Another container of iax2_pvt structures.

Active IAX2 pvt structs are also stored in this container, if they are a part of an active call where we know the remote side's call number. The reason for this is that incoming media frames do not contain our call number. So, instead of having to iterate the entire iaxs array, we use this container to look up calls where the remote side is using a given call number.

Definition at line 1021 of file chan_iax2.c.

Another container of iax2_pvt structures.

* Active IAX2 pvt stucts used during transfering a call are stored here.

Definition at line 1037 of file chan_iax2.c.

int iaxactivethreadcount = 0 [static]

Definition at line 585 of file chan_iax2.c.

Referenced by iax2_process_thread(), and iax2_process_thread_cleanup().

int iaxcompat = 0 [static]

Definition at line 244 of file chan_iax2.c.

int iaxdebug = 0 [static]

Definition at line 316 of file chan_iax2.c.

int iaxdefaultdpcache = 10 * 60 [static]

Definition at line 247 of file chan_iax2.c.

Referenced by complete_dpreply(), and find_cache().

int iaxdefaulttimeout = 5 [static]

Definition at line 249 of file chan_iax2.c.

int iaxdynamicthreadcount = 0 [static]

Definition at line 583 of file chan_iax2.c.

Referenced by find_idle_thread(), and iax2_process_thread().

int iaxdynamicthreadnum = 0 [static]

Definition at line 584 of file chan_iax2.c.

Referenced by find_idle_thread().

int iaxmaxthreadcount = DEFAULT_MAX_THREAD_COUNT [static]

Definition at line 582 of file chan_iax2.c.

Referenced by find_idle_thread(), and set_config().

Initial value:
 {
   .name = "IAXPEER",
   .read = function_iaxpeer,
}

Definition at line 13444 of file chan_iax2.c.

struct chan_iax2_pvt* iaxs[IAX_MAX_CALLS+1] [static]

an array of iax2 pvt structures

The container for active chan_iax2_pvt structures is implemented as an array for extremely quick direct access to the correct pvt structure based on the local call number. The local call number is used as the index into the array where the associated pvt structure is stored.

Definition at line 1010 of file chan_iax2.c.

ast_mutex_t iaxsl[ARRAY_LEN(iaxs)] [static]

chan_iax2_pvt structure locks

These locks are used when accessing a pvt structure in the iaxs array. The index used here is the same as used in the iaxs array. It is the local call number for the associated pvt struct.

Definition at line 1030 of file chan_iax2.c.

int iaxthreadcount = DEFAULT_THREAD_COUNT [static]

Definition at line 581 of file chan_iax2.c.

Referenced by handle_cli_iax2_show_threads(), set_config(), and start_network_thread().

int iaxtrunkdebug = 0 [static]

Definition at line 318 of file chan_iax2.c.

Initial value:
 {
   .name = "IAXVAR",
   .read = acf_iaxvar_read,
   .write = acf_iaxvar_write,
}

Definition at line 9487 of file chan_iax2.c.

struct idle_list idle_list [static]
struct io_context* io [static]

Definition at line 311 of file chan_iax2.c.

int jittertargetextra = 40 [static]

Definition at line 235 of file chan_iax2.c.

Referenced by new_iax().

int lagrq_time = 10 [static]

Definition at line 231 of file chan_iax2.c.

char language[MAX_LANGUAGE] = "" [static]

Definition at line 225 of file chan_iax2.c.

int last_authmethod = 0 [static]

Definition at line 245 of file chan_iax2.c.

const time_t MAX_CALLTOKEN_DELAY = 10 [static]

Definition at line 814 of file chan_iax2.c.

int max_reg_expire [static]

Definition at line 257 of file chan_iax2.c.

Referenced by set_config(), and update_registry().

int max_retries = 4 [static]

Definition at line 229 of file chan_iax2.c.

int maxauthreq = 3 [static]

Definition at line 228 of file chan_iax2.c.

Referenced by build_user().

int maxjitterbuffer = 1000 [static]

Definition at line 232 of file chan_iax2.c.

Referenced by new_iax().

int maxjitterinterps = 10 [static]

Definition at line 234 of file chan_iax2.c.

Referenced by new_iax().

int maxnontrunkcall = 1 [static]

Definition at line 1111 of file chan_iax2.c.

Referenced by __find_callno().

int maxtrunkcall = TRUNK_CALL_START [static]

Definition at line 1110 of file chan_iax2.c.

Referenced by __find_callno().

int min_reg_expire [static]

Definition at line 256 of file chan_iax2.c.

Referenced by __expire_registry(), __find_callno(), build_peer(), and update_registry().

char mohinterpret[MAX_MUSICCLASS] [static]

Definition at line 329 of file chan_iax2.c.

char mohsuggest[MAX_MUSICCLASS] [static]
struct ast_netsock_list* netsock [static]

Definition at line 263 of file chan_iax2.c.

pthread_t netthreadid = AST_PTHREADT_NULL [static]

Definition at line 338 of file chan_iax2.c.

struct ast_netsock_list* outsock [static]

used if sourceaddress specified and bindaddr == INADDR_ANY

Definition at line 264 of file chan_iax2.c.

char* papp = "IAX2Provision" [static]

Definition at line 11414 of file chan_iax2.c.

struct ao2_container* peercnts [static]

Table containing peercnt objects for every ip address consuming a callno

Definition at line 834 of file chan_iax2.c.

struct ao2_container* peers [static]

Definition at line 828 of file chan_iax2.c.

int ping_time = 21 [static]

Definition at line 230 of file chan_iax2.c.

struct { ... } qos [static]

Referenced by peer_set_srcaddr(), and set_config().

int randomcalltokendata [static]

Definition at line 812 of file chan_iax2.c.

char regcontext[AST_MAX_CONTEXT] = "" [static]

Definition at line 226 of file chan_iax2.c.

struct registrations registrations [static]
int resyncthreshold = 1000 [static]

Definition at line 233 of file chan_iax2.c.

Referenced by new_iax().

struct ast_sched_thread* sched [static]

Definition at line 312 of file chan_iax2.c.

int srvlookup = 0 [static]

Definition at line 259 of file chan_iax2.c.

Referenced by build_peer().

const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)" [static]

Definition at line 211 of file chan_iax2.c.

int test_losspct = 0 [static]

Definition at line 320 of file chan_iax2.c.

unsigned int tos

Definition at line 252 of file chan_iax2.c.

uint16_t total_nonval_callno_used = 0 [static]

Definition at line 851 of file chan_iax2.c.

struct tpeers tpeers [static]

Definition at line 219 of file chan_iax2.c.

Referenced by handle_cli_iax2_show_stats().

Trunk MTU statistics

Definition at line 219 of file chan_iax2.c.

int trunk_timed [static]

Definition at line 219 of file chan_iax2.c.

Definition at line 219 of file chan_iax2.c.

int trunkfreq = 20 [static]

Definition at line 239 of file chan_iax2.c.

int trunkmaxsize = MAX_TRUNKDATA [static]

Definition at line 240 of file chan_iax2.c.

struct ao2_container* users [static]

Definition at line 831 of file chan_iax2.c.