Skip to content
Snippets Groups Projects
chan_iax2.c 321 KiB
Newer Older
 * Asterisk -- An open source telephony toolkit.
 * Copyright (C) 1999 - 2006, Digium, Inc.
 *
 * Mark Spencer <markster@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

 * \brief Implementation of Inter-Asterisk eXchange Version 2
 * \author Mark Spencer <markster@digium.com>
 *
Russell Bryant's avatar
Russell Bryant committed
 * \par See also
 * \arg \ref Config_iax
 *
 * \ingroup channel_drivers
Kevin P. Fleming's avatar
Kevin P. Fleming committed
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
Kevin P. Fleming's avatar
Kevin P. Fleming committed
#include <sys/mman.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
Mark Spencer's avatar
Mark Spencer committed
#include <arpa/inet.h>
Kevin P. Fleming's avatar
Kevin P. Fleming committed
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
Kevin P. Fleming's avatar
Kevin P. Fleming committed
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <regex.h>
#ifdef IAX_TRUNKING
#include <sys/ioctl.h>
#ifdef __linux__
#include <linux/zaptel.h>
#else
#include <zaptel.h>
#endif /* __linux__ */
#endif

Kevin P. Fleming's avatar
Kevin P. Fleming committed
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "asterisk/frame.h" 
#include "asterisk/channel.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/config.h"
#include "asterisk/options.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/stringfields.h"
#include "iax2.h"
#include "iax2-parser.h"
#include "iax2-provision.h"
/* Define NEWJB to use the new channel independent jitterbuffer,
 * otherwise, use the old jitterbuffer */
#define NEWJB

Mark Spencer's avatar
Mark Spencer committed
/* Define SCHED_MULTITHREADED to run the scheduler in a special
   multithreaded mode. */
Russell Bryant's avatar
Russell Bryant committed
#define SCHED_MULTITHREADED
/* Define DEBUG_SCHED_MULTITHREADED to keep track of where each
   thread is actually doing. */
Russell Bryant's avatar
Russell Bryant committed
#define DEBUG_SCHED_MULTITHREAD
Mark Spencer's avatar
Mark Spencer committed
#ifndef IPTOS_MINCOST
#define IPTOS_MINCOST 0x02
#endif

#ifdef SO_NO_CHECK
static int nochecksums = 0;
#endif

/*
 * Uncomment to try experimental IAX bridge optimization,
 * designed to reduce latency when IAX calls cannot
Mark Spencer's avatar
Mark Spencer committed
 * be trasnferred -- obsolete
Mark Spencer's avatar
Mark Spencer committed
/* #define BRIDGE_OPTIMIZATION  */

#define PTR_TO_CALLNO(a) ((unsigned short)(unsigned long)(a))
#define CALLNO_TO_PTR(a) ((void *)(unsigned long)(a))
Mark Spencer's avatar
Mark Spencer committed
#define DEFAULT_THREAD_COUNT 10
#define DEFAULT_RETRY_TIME 1000
#define MEMORY_SIZE 100
#define DEFAULT_DROP 3
/* Flag to use with trunk calls, keeping these calls high up.  It halves our effective use
   but keeps the division between trunked and non-trunked better. */
#define TRUNK_CALL_START	0x4000

#define DEBUG_SUPPORT

#define MIN_REUSE_TIME		60	/* Don't reuse a call number within 60 seconds */

/* Sample over last 100 units to determine historic jitter */
#define GAMMA (0.01)

static struct ast_codec_pref prefs;

static const char desc[] = "Inter Asterisk eXchange (Ver 2)";
static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";

static char context[80] = "default";

static char language[MAX_LANGUAGE] = "";
static char regcontext[AST_MAX_CONTEXT] = "";
static int max_retries = 4;
static int ping_time = 20;
static int lagrq_time = 10;
static int maxtrunkcall = TRUNK_CALL_START;
static int maxnontrunkcall = 1;
static int maxjitterbuffer=1000;
#ifdef NEWJB
static int resyncthreshold=1000;
static int jittershrinkrate=2;
static int trunkfreq = 20;
Mark Spencer's avatar
Mark Spencer committed
static int authdebug = 1;
Mark Spencer's avatar
Mark Spencer committed
static int autokill = 0;

static int iaxdefaultdpcache=10 * 60;	/* Cache dialplan entries for 10 minutes by default */

static int iaxdefaulttimeout = 5;		/* Default to wait no more than 5 seconds for a reply to come back */

static int tos = 0;

static int min_reg_expire;
static int max_reg_expire;
static int timingfd = -1;				/* Timing file descriptor */

static int usecnt;
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
int (*iax2_regfunk)(char *username, int onoff) = NULL;

/* Ethernet, etc */
#define IAX_CAPABILITY_FULLBANDWIDTH 	0xFFFF
/* T1, maybe ISDN */
Russell Bryant's avatar
Russell Bryant committed
#define IAX_CAPABILITY_MEDBANDWIDTH 	(IAX_CAPABILITY_FULLBANDWIDTH & 	\
							~AST_FORMAT_SLINEAR & 	\
							~AST_FORMAT_ULAW & 	\
							~AST_FORMAT_ALAW) 
/* A modem */
Russell Bryant's avatar
Russell Bryant committed
#define IAX_CAPABILITY_LOWBANDWIDTH		(IAX_CAPABILITY_MEDBANDWIDTH & 	\
							~AST_FORMAT_G726 & 	\
							~AST_FORMAT_ADPCM)
Russell Bryant's avatar
Russell Bryant committed
#define IAX_CAPABILITY_LOWFREE		(IAX_CAPABILITY_LOWBANDWIDTH & 		\
							 ~AST_FORMAT_G723_1)


#define DEFAULT_MAXMS		2000		/* Must be faster than 2 seconds by default */
Russell Bryant's avatar
Russell Bryant committed
#define DEFAULT_FREQ_OK		60 * 1000	/* How often to check for the host to be up */
#define DEFAULT_FREQ_NOTOK	10 * 1000	/* How often to check, if the host is down... */

static	struct io_context *io;
static	struct sched_context *sched;

static int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;

static int iax2_dropcount = DEFAULT_DROP;

static int iaxdebug = 0;

static int iaxtrunkdebug = 0;

#ifdef IAXTESTS
static int test_late = 0;
static int test_resync = 0;
static int test_jit = 0;
static int test_jitpct = 0;
#endif /* IAXTESTS */
static char accountcode[AST_MAX_ACCOUNT_CODE];
static int amaflags = 0;
static struct ast_flags globalflags = { 0 };
static pthread_t netthreadid = AST_PTHREADT_NULL;
Mark Spencer's avatar
Mark Spencer committed
static pthread_t schedthreadid = AST_PTHREADT_NULL;
AST_MUTEX_DEFINE_STATIC(sched_lock);
static int sched_halt = 0;
static ast_cond_t sched_cond;
enum {
	IAX_STATE_STARTED = 		(1 << 0),
	IAX_STATE_AUTHENTICATED = 	(1 << 1),
	IAX_STATE_TBD = 		(1 << 2),
	IAX_STATE_UNCHANGED = 		(1 << 3),

struct iax2_context {
	char context[AST_MAX_CONTEXT];
	struct iax2_context *next;
};

enum {
	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 */
} iax2_flags;

static int global_rtautoclear = 120;
static int reload_config(void);
static int iax2_reload(int fd, int argc, char *argv[]);

struct iax2_user {
	char name[80];
	char secret[80];
	char dbsecret[80];
	int authmethods;
	char accountcode[AST_MAX_ACCOUNT_CODE];
	char inkeys[80];				/*!< Key(s) this user can use to authenticate to us */
	char language[MAX_LANGUAGE];
	int amaflags;
	unsigned int flags;
	char cid_num[AST_MAX_EXTENSION];
	char cid_name[AST_MAX_EXTENSION];
	struct ast_codec_pref prefs;
	struct ast_ha *ha;
	struct iax2_context *contexts;
	struct iax2_user *next;
	struct ast_variable *vars;
};

struct iax2_peer {
	char name[80];
	char username[80];		
	char secret[80];
	char dbsecret[80];
	char outkey[80];				/*!< What key we use to talk to this peer */
	char context[AST_MAX_CONTEXT];			/*!< For transfers only */
	char regexten[AST_MAX_EXTENSION];		/*!< Extension to register (if regcontext is used) */
	char peercontext[AST_MAX_EXTENSION];		/*!< Context to pass to peer */
	char mailbox[AST_MAX_EXTENSION];		/*!< Mailbox */
	struct ast_codec_pref prefs;
	struct ast_dnsmgr_entry *dnsmgr;		/*!< DNS refresh manager */
	struct sockaddr_in addr;
	int formats;
	int sockfd;					/*!< Socket to use for transmission */
	struct in_addr mask;
	unsigned int flags;

	/* Dynamic Registration fields */
	struct sockaddr_in defaddr;			/*!< Default address if there is one */
	int authmethods;				/*!< Authentication methods (IAX_AUTH_*) */
	int encmethods;					/*!< Encryption methods (IAX_ENCRYPT_*) */
	char inkeys[80];				/*!< Key(s) this peer can use to authenticate to us */

	/* Suggested caller id if registering */
	char cid_num[AST_MAX_EXTENSION];		/*!< Default context (for transfer really) */
	char cid_name[AST_MAX_EXTENSION];		/*!< Default context (for transfer really) */
	int expire;					/*!< Schedule entry for expiry */
	int expiry;					/*!< How soon to expire */
	int capability;					/*!< Capability */
	char zonetag[80];				/*!< Time Zone */

	/* Qualification */
	int callno;					/*!< Call number of POKE request */
	int pokeexpire;					/*!< When to expire poke */
	int lastms;					/*!< How long last response took (in ms), or -1 for no response */
	int maxms;					/*!< Max ms we will accept for the host to be up, 0 to not monitor */

	int pokefreqok;					/*!< How often to check if the host is up */
	int pokefreqnotok;				/*!< How often to check when the host has been determined to be down */
	int historicms;					/*!< How long recent average responses took */
	int smoothing;					/*!< Sample over how many units to determine historic ms */
	
	struct ast_ha *ha;
	struct iax2_peer *next;
};

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

static struct iax2_trunk_peer {
	ast_mutex_t lock;
	struct sockaddr_in addr;
	struct timeval txtrunktime;		/*!< Transmit trunktime */
	struct timeval rxtrunktime;		/*!< Receive trunktime */
	struct timeval lasttxtime;		/*!< Last transmitted trunktime */
	struct timeval trunkact;		/*!< Last trunk activity */
	unsigned int lastsent;			/*!< Last sent time */
	/* Trunk data and length */
	unsigned char *trunkdata;
	unsigned int trunkdatalen;
	unsigned int trunkdataalloc;
	struct iax2_trunk_peer *next;
	int trunkerror;
	int calls;
} *tpeers = NULL;

AST_MUTEX_DEFINE_STATIC(tpeerlock);
struct iax_firmware {
	struct iax_firmware *next;
	int fd;
	int mmaplen;
	int dead;
	struct ast_iax2_firmware_header *fwh;
	unsigned char *buf;
};

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
};

struct iax2_registry {
	struct sockaddr_in addr;		/*!< Who we connect to for registration purposes */
	char username[80];
	char secret[80];			/*!< Password or key name in []'s */
	char random[80];
	int expire;				/*!< Sched ID of expiration */
	int refresh;				/*!< How often to refresh */
	int messages;				/*!< Message count */
	int callno;				/*!< Associated call number if applicable */
	struct sockaddr_in us;			/*!< Who the server thinks we are */
	struct iax2_registry *next;
};

static struct iax2_registry *registrations;

/* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
Russell Bryant's avatar
Russell Bryant committed
#define MIN_RETRY_TIME		100
#define MAX_RETRY_TIME  	10000
Russell Bryant's avatar
Russell Bryant committed
#define MAX_JITTER_BUFFER 	50
#define MIN_JITTER_BUFFER 	10
#define DEFAULT_TRUNKDATA	640 * 10	/*!< 40ms, uncompressed linear * 10 channels */
#define MAX_TRUNKDATA		640 * 200	/*!< 40ms, uncompressed linear * 200 channels */
#define MAX_TIMESTAMP_SKEW	160		/*!< maximum difference between actual and predicted ts for sending */
/* If consecutive voice frame timestamps jump by more than this many milliseconds, then jitter buffer will resync */
#define TS_GAP_FOR_JB_RESYNC	5000

/* If we have more than this much excess real jitter buffer, shrink it. */
static int max_jitter_buffer = MAX_JITTER_BUFFER;
/* If we have less than this much excess real jitter buffer, enlarge it. */
static int min_jitter_buffer = MIN_JITTER_BUFFER;
Mark Spencer's avatar
Mark Spencer committed
static int iaxthreadcount = DEFAULT_THREAD_COUNT;

struct iax_rr {
	int jitter;
	int losspct;
	int losscnt;
	int packets;
	int delay;
	int dropped;
	int ooo;
};

struct chan_iax2_pvt {
	/*! Socket to send/receive on for this call */
	/*! Last received voice format */
	int voiceformat;
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	/*! Last received video format */
	int videoformat;
	int svoiceformat;
	int svideoformat;
	/*! What we are capable of sending */
	int capability;
	unsigned int last;
	/*! Last sent timestamp - never send the same timestamp twice in a single call */
	unsigned int lastsent;
	/*! Next outgoing timestamp if everything is good */
	unsigned int nextpred;
	/*! True if the last voice we transmitted was not silence/CNG */
	int notsilenttx;
	unsigned int pingtime;
	/*! Max time for initial response */
	int maxtime;
	struct sockaddr_in addr;
	struct ast_codec_pref prefs;
	unsigned short callno;
	unsigned short peercallno;
	int peerformat;
	int peercapability;
	/*! timeval that we base our transmission on */
	struct timeval offset;
	/*! timeval that we base our delivery on */
	struct timeval rxcore;
	/*! active jb read scheduler id */
	int history[MEMORY_SIZE];
	int jitterbuffer;
	int jitter;
	int historicjitter;
	int lag;
	/*! Error, as discovered by the manager */
	int error;
	struct ast_channel *owner;
	struct ast_flags state;
	/*! Next outgoing sequence number */
	unsigned char oseqno;
	/*! Next sequence number they have not yet acknowledged */
	unsigned char rseqno;
	/*! Next incoming sequence number */
	unsigned char iseqno;
	/*! Last incoming sequence number we have acknowledged */
	unsigned char aseqno;
	char peer[80];
	char context[80];
	char cid_num[80];
	char cid_name[80];
	/*! Hidden Caller ID (i.e. ANI) if appropriate */
	char ani[80];
	char dnid[80];
	/*! RDNIS */
	char rdnis[80];
	char exten[AST_MAX_EXTENSION];
	char username[80];
	char secret[80];
	/*! permitted authentication methods */
	int authmethods;
	/*! permitted encryption methods */
	char challenge[10];
	/*! Public keys permitted keys for incoming authentication */
	char inkeys[80];
	/*! Private key for outgoing authentication */
	char outkey[80];
	/*! 32 bytes of semi-random data */
	char language[MAX_LANGUAGE];
	/*! Hostname/peername for naming purposes */
	char host[80];
	struct iax2_registry *reg;
	/*! Associated peer for poking */
	struct iax2_peer *peerpoke;
	unsigned int flags;
	enum iax_transfer_state transferring;
	/*! Who we are IAX transfering to */
	struct sockaddr_in transfer;
	/*! What's the new call number for the transfer */
	unsigned short transfercallno;
	/*! Transfer decrypt AES-128 Key */
	/*! Status of knowledge of peer ADSI capability */
	int peeradsicpe;
	
	unsigned short bridgecallno;
	unsigned int bridgesfmt;
	struct ast_trans_pvt *bridgetrans;
	
	int pingid;			/*!< Transmit PING request */
	int lagid;			/*!< Retransmit lag request */
	int autoid;			/*!< Auto hangup for Dialplan requestor */
	int authid;			/*!< Authentication rejection ID */
	int authfail;			/*!< Reason to report failure */
	int initid;			/*!< Initial peer auto-congest ID (based on qualified peers) */
	int calling_ton;
	int calling_tns;
	int calling_pres;
	char dproot[AST_MAX_EXTENSION];
	char accountcode[AST_MAX_ACCOUNT_CODE];
	int amaflags;
	struct iax2_dpcache *dpentries;
	struct ast_variable *vars;
	struct iax_rr remote_rr;
	/*! Current base time: (just for stats) */
	/*! Dropped frame count: (just for stats) */
	/*! received frame count: (just for stats) */
};

static struct ast_iax2_queue {
Mark Spencer's avatar
Mark Spencer committed
	struct iax_frame *head;
	struct iax_frame *tail;
	int count;
} iaxq;

static struct ast_user_list {
	struct iax2_user *users;
} userl;

static struct ast_peer_list {
	struct iax2_peer *peers;
static struct ast_firmware_list {
	struct iax_firmware *wares;
	ast_mutex_t lock;
} waresl;

#define CACHE_FLAG_EXISTS		(1 << 0)
Russell Bryant's avatar
Russell Bryant committed
#define CACHE_FLAG_NONEXISTENT		(1 << 1)
#define CACHE_FLAG_CANEXIST		(1 << 2)
/*! Waiting to hear back response */
#define CACHE_FLAG_PENDING		(1 << 3)
#define CACHE_FLAG_TIMEOUT		(1 << 4)
Russell Bryant's avatar
Russell Bryant committed
#define CACHE_FLAG_TRANSMITTED		(1 << 5)
#define CACHE_FLAG_UNKNOWN		(1 << 6)
Russell Bryant's avatar
Russell Bryant committed
#define CACHE_FLAG_MATCHMORE		(1 << 7)

static struct iax2_dpcache {
	char peercontext[AST_MAX_CONTEXT];
	char exten[AST_MAX_EXTENSION];
	struct timeval orig;
	int flags;
	unsigned short callno;
	int waiters[256];
	struct iax2_dpcache *next;
	struct iax2_dpcache *peer;	/*!< For linking in peers */
static void reg_source_db(struct iax2_peer *p);
static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
static void destroy_peer(struct iax2_peer *peer);
static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
Mark Spencer's avatar
Mark Spencer committed
#define IAX_IOSTATE_IDLE		0
#define IAX_IOSTATE_READY		1
#define IAX_IOSTATE_PROCESSING	2
#define IAX_IOSTATE_SCHEDREADY	3

struct iax2_thread {
	ASTOBJ_COMPONENTS(struct iax2_thread);
	int iostate;
#ifdef SCHED_MULTITHREADED
	void (*schedfunc)(void *);
	void *scheddata;
#endif
#ifdef DEBUG_SCHED_MULTITHREAD
	char curfunc[80];
#endif	
Mark Spencer's avatar
Mark Spencer committed
	int actions;
	int halt;
	pthread_t threadid;
	int threadnum;
	struct sockaddr_in iosin;
	unsigned char buf[4096]; 
	int iores;
	int iofd;
	time_t checktime;
Mark Spencer's avatar
Mark Spencer committed
};

struct iax2_thread_list {
	ASTOBJ_CONTAINER_COMPONENTS(struct iax2_thread);
};

static struct iax2_thread_list idlelist, activelist;

static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
{
	ast_mutex_lock(lock);
	ast_cond_signal(cond);
	ast_mutex_unlock(lock);
}

static void iax_debug_output(const char *data)
	if (iaxdebug)
James Golovich's avatar
James Golovich committed
		ast_verbose("%s", data);
static void iax_error_output(const char *data)
James Golovich's avatar
James Golovich committed
	ast_log(LOG_WARNING, "%s", data);
#ifdef NEWJB
static void jb_error_output(const char *fmt, ...)
{
	va_list args;
	char buf[1024];

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

	ast_log(LOG_ERROR, buf);
}

static void jb_warning_output(const char *fmt, ...)
{
	va_list args;
	char buf[1024];

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

	ast_log(LOG_WARNING, buf);
}

static void jb_debug_output(const char *fmt, ...)
{
	va_list args;
	char buf[1024];

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

	ast_verbose(buf);
}
#endif


/* XXX We probably should use a mutex when working with this XXX */
static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
static ast_mutex_t iaxsl[IAX_MAX_CALLS];
static struct timeval lastused[IAX_MAX_CALLS];
static int send_command(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_immediate(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_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly);
static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly);
static void destroy_user(struct iax2_user *user);
static int expire_registry(void *data);
static int iax2_write(struct ast_channel *c, struct ast_frame *f);
static int iax2_do_register(struct iax2_registry *reg);
static void prune_peers(void);
static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
Mark Spencer's avatar
Mark Spencer committed
static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
static int iax2_devicestate(void *data);
static int iax2_digit(struct ast_channel *c, char digit);
static int iax2_sendtext(struct ast_channel *c, const char *text);
static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
static int iax2_call(struct ast_channel *c, char *dest, int timeout);
static int iax2_hangup(struct ast_channel *c);
static int iax2_answer(struct ast_channel *c);
static struct ast_frame *iax2_read(struct ast_channel *c);
static int iax2_write(struct ast_channel *c, struct ast_frame *f);
static int iax2_indicate(struct ast_channel *c, int condition);
static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen);
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_transfer(struct ast_channel *c, const char *dest);
static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);

static const struct ast_channel_tech iax2_tech = {
	.description = tdesc,
	.capabilities = IAX_CAPABILITY_FULLBANDWIDTH,
	.requester = iax2_request,
	.devicestate = iax2_devicestate,
	.send_digit = iax2_digit,
	.send_text = iax2_sendtext,
	.send_image = iax2_sendimage,
	.send_html = iax2_sendhtml,
	.call = iax2_call,
	.hangup = iax2_hangup,
	.answer = iax2_answer,
	.read = iax2_read,
	.write = iax2_write,
	.write_video = iax2_write,
	.indicate = iax2_indicate,
	.setoption = iax2_setoption,
	.bridge = iax2_bridge,
	.transfer = iax2_transfer,
	.fixup = iax2_fixup,
};
Mark Spencer's avatar
Mark Spencer committed
static struct iax2_thread *find_idle_thread(void)
{
	struct iax2_thread *thread;
	thread = ASTOBJ_CONTAINER_UNLINK_START(&idlelist);
	return thread;
}

#ifdef SCHED_MULTITHREADED
static int __schedule_action(void (*func)(void *data), void *data, const char *funcname)
Mark Spencer's avatar
Mark Spencer committed
{
	struct iax2_thread *thread;
	static time_t lasterror;
	static time_t t;
	thread = find_idle_thread();
	if (thread) {
		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);
Mark Spencer's avatar
Mark Spencer committed
		return 0;
	}
	time(&t);
	if (t != lasterror) 
		ast_log(LOG_NOTICE, "Out of idle IAX2 threads for scheduling!\n");
	lasterror = t;
	return -1;
}
#define schedule_action(func, data) __schedule_action(func, data, __PRETTY_FUNCTION__)
Mark Spencer's avatar
Mark Spencer committed
#endif

static void __send_ping(void *data)
{
	int callno = (long)data;
	send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
}

static int send_ping(void *data)
{
	int callno = (long)data;
	if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
Mark Spencer's avatar
Mark Spencer committed
		if (!iaxs[callno]->bridgecallno) 
Mark Spencer's avatar
Mark Spencer committed
		{		
#ifdef SCHED_MULTITHREADED
			if (schedule_action(__send_ping, data))
#endif		
				__send_ping(data);
		}
		return 1;
	} else
		return 0;
Mark Spencer's avatar
Mark Spencer committed
	return 0;
static int get_encrypt_methods(const char *s)
{
	int e;
	if (!strcasecmp(s, "aes128"))
		e = IAX_ENCRYPT_AES128;
	else if (ast_true(s))
		e = IAX_ENCRYPT_AES128;
	else
		e = 0;
	return e;
}

Mark Spencer's avatar
Mark Spencer committed
static void __send_lagrq(void *data)
{
	int callno = (long)data;
	/* Ping only if it's real not if it's bridged */
Mark Spencer's avatar
Mark Spencer committed
	send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
}

static int send_lagrq(void *data)
{
	int callno = (long)data;
	if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
Mark Spencer's avatar
Mark Spencer committed
		if (!iaxs[callno]->bridgecallno) 
#endif
		{		
#ifdef SCHED_MULTITHREADED
			if (schedule_action(__send_lagrq, data))
Mark Spencer's avatar
Mark Spencer committed
				__send_lagrq(data);
		}
		return 1;
	} else
		return 0;
Mark Spencer's avatar
Mark Spencer committed
	return 0;
}

static unsigned char compress_subclass(int subclass)
{
	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 uncompress_subclass(unsigned char csub)
{
	/* 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);
static struct iax2_peer *find_peer(const char *name, int realtime) 
{
	struct iax2_peer *peer;
	ast_mutex_lock(&peerl.lock);
	for(peer = peerl.peers; peer; peer = peer->next) {
		if (!strcasecmp(peer->name, name)) {
			break;
		}
	}
	ast_mutex_unlock(&peerl.lock);
	if(!peer && realtime)
		peer = realtime_peer(name, NULL);
static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
{
	struct iax2_peer *peer;
	int res = 0;
Russell Bryant's avatar
Russell Bryant committed

	if (lockpeer)
	peer = peerl.peers;
Russell Bryant's avatar
Russell Bryant committed
	while (peer) {
		if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
				(peer->addr.sin_port == sin.sin_port)) {
					res = 1;
					break;
		}
		peer = peer->next;
	}
	if (lockpeer)
	if (!peer) {
		peer = realtime_peer(NULL, &sin);
		if (peer) {
			ast_copy_string(host, peer->name, len);
			if (ast_test_flag(peer, IAX_TEMPONLY))