Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Implementation of Inter-Asterisk eXchange Version 2
*
* Copyright (C) 2003 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
Kevin P. Fleming
committed
#include "asterisk.h"
Kevin P. Fleming
committed
Kevin P. Fleming
committed
#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"
Kevin P. Fleming
committed
#include "asterisk/devicestate.h"
Kevin P. Fleming
committed
#include "asterisk/netsock.h"
Kevin P. Fleming
committed
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#ifdef IAX_TRUNKING
#include <sys/ioctl.h>
#else
#include <zaptel.h>
#endif /* __linux__ */
Mark Spencer
committed
/* Define NEWJB to use the new channel independent jitterbuffer,
* otherwise, use the old jitterbuffer */
#define NEWJB
#ifdef NEWJB
#include "../jitterbuf.h"
#endif
#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
#define PTR_TO_CALLNO(a) ((unsigned short)(unsigned long)(a))
#define CALLNO_TO_PTR(a) ((void *)(unsigned long)(a))
#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 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 const char channeltype[] = "IAX2";
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;
Kevin P. Fleming
committed
static int maxjitterinterps=10;
static int jittershrinkrate=2;
Mark Spencer
committed
static int send_trunktimestamps = 1;
Mark Spencer
committed
static int iaxcompat = 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 expirey = IAX_DEFAULT_REG_EXPIRE;
static int timingfd = -1; /* Timing file descriptor */
Kevin P. Fleming
committed
static struct ast_netsock_list *netsock;
static int defaultsockfd = -1;
AST_MUTEX_DEFINE_STATIC(usecnt_lock);
int (*iax2_regfunk)(char *username, int onoff) = NULL;
/* Ethernet, etc */
#define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
/* T1, maybe ISDN */
#define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
~AST_FORMAT_SLINEAR & \
~AST_FORMAT_ULAW & \
~AST_FORMAT_ALAW)
#define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
~AST_FORMAT_G726 & \
~AST_FORMAT_ADPCM)
#define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
~AST_FORMAT_G723_1)
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
#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;
Mark Spencer
committed
static int test_losspct = 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 */
Mark Spencer
committed
static char accountcode[AST_MAX_ACCOUNT_CODE];
Mark Spencer
committed
static int delayreject = 0;
Mark Spencer
committed
static int iax2_encryption = 0;
static struct ast_flags globalflags = {0};
static pthread_t netthreadid = AST_PTHREADT_NULL;
#define IAX_STATE_AUTHENTICATED (1 << 1)
#define IAX_STATE_TBD (1 << 2)
struct iax2_context {
char context[AST_MAX_CONTEXT];
#define IAX_HASCALLERID (1 << 0) /* CallerID has been specified */
#define IAX_DELME (1 << 1) /* Needs to be deleted */
#define IAX_TEMPONLY (1 << 2) /* Temporary (realtime) */
#define IAX_TRUNK (1 << 3) /* Treat as a trunk */
#define IAX_NOTRANSFER (1 << 4) /* Don't native bridge */
#define IAX_USEJITTERBUF (1 << 5) /* Use jitter buffer */
#define IAX_DYNAMIC (1 << 6) /* dynamic peer */
#define IAX_SENDANI (1 << 7) /* Send ANI along with CallerID */
#define IAX_MESSAGEDETAIL (1 << 8) /* Show exact numbers */
#define IAX_ALREADYGONE (1 << 9) /* Already disconnected */
#define IAX_PROVISION (1 << 10) /* This is a provisioning request */
#define IAX_QUELCH (1 << 11) /* Whether or not we quelch audio */
#define IAX_ENCRYPTED (1 << 12) /* Whether we should assume encrypted tx/rx */
#define IAX_KEYPOPULATED (1 << 13) /* Whether we have a key populated */
#define IAX_CODEC_USER_FIRST (1 << 14) /* are we willing to let the other guy choose the codec? */
#define IAX_CODEC_NOPREFS (1 << 15) /* Force old behaviour by turning off prefs */
#define IAX_CODEC_NOCAP (1 << 16) /* only consider requested format and ignore capabilities*/
#define IAX_RTCACHEFRIENDS (1 << 17) /* let realtime stay till your reload */
#define IAX_RTNOUPDATE (1 << 18) /* Don't send a realtime update */
#define IAX_RTAUTOCLEAR (1 << 19) /* erase me on expire */
Mark Spencer
committed
#define IAX_FORCEJITTERBUF (1 << 20) /* Force jitterbuffer, even when bridged to a channel that can take jitter */
static int global_rtautoclear = 120;
static int reload_config(void);
Kevin P. Fleming
committed
static int iax2_reload(int fd, int argc, char *argv[]);
struct iax2_user {
char name[80];
char secret[80];
Mark Spencer
committed
int encmethods;
char accountcode[AST_MAX_ACCOUNT_CODE];
char inkeys[80]; /* Key(s) this user can use to authenticate to us */
char language[MAX_LANGUAGE];
int capability;
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 iax2_peer {
char name[80];
char username[80];
char secret[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 sockaddr_in defaddr; /* Default address if there is one */
int authmethods; /* Authentication methods (IAX_AUTH_*) */
Mark Spencer
committed
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 expirey */
int expirey; /* 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 */
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;
int sockfd;
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;
};
#define REG_STATE_UNREGISTERED 0
#define REG_STATE_REGSENT 1
#define REG_STATE_AUTHSENT 2
#define REG_STATE_REGISTERED 3
#define REG_STATE_REJECTED 4
#define REG_STATE_TIMEOUT 5
#define REG_STATE_NOAUTH 6
#define TRANSFER_NONE 0
#define TRANSFER_BEGIN 1
#define TRANSFER_READY 2
#define TRANSFER_RELEASED 3
#define TRANSFER_PASSTHROUGH 4
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 */
#define MIN_RETRY_TIME 100
#define MAX_RETRY_TIME 10000
#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;
struct iax_rr {
int jitter;
int losspct;
int losscnt;
int packets;
int delay;
int dropped;
int ooo;
};
/* Socket to send/receive on for this call */
int sockfd;
/* Last received voice format */
int voiceformat;
/* Last received voice format */
int videoformat;
/* Last sent voice format */
int svoiceformat;
/* Last sent video format */
int svideoformat;
/* What we are capable of sending */
int capability;
/* Last received timestamp */
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;
/* Ping time */
unsigned int pingtime;
/* Max time for initial response */
int maxtime;
/* Peer Address */
struct sockaddr_in addr;
struct ast_codec_pref prefs;
/* Our call number */
unsigned short callno;
/* Peer callno */
unsigned short peercallno;
/* Peer selected format */
int peerformat;
/* Peer capability */
int peercapability;
/* timeval that we base our transmission on */
struct timeval offset;
/* timeval that we base our delivery on */
struct timeval rxcore;
Mark Spencer
committed
#ifdef NEWJB
/* The jitterbuffer */
jitterbuf *jb;
/* active jb read scheduler id */
int jbid;
#else
/* Historical delivery time */
int history[MEMORY_SIZE];
/* Current base jitterbuffer */
int jitterbuffer;
/* Current jitter measure */
int jitter;
/* Historic jitter value */
int historicjitter;
Mark Spencer
committed
#endif
/* LAG */
int lag;
/* Error, as discovered by the manager */
int error;
/* Owner if we have one */
struct ast_channel *owner;
/* What's our state? */
int state;
/* Expirey (optional) */
int expirey;
/* Next outgoing sequence number */
/* Next sequence number they have not yet acknowledged */
/* Last incoming sequence number we have acknowledged */
/* Peer name */
char peer[80];
/* Default Context */
char context[80];
/* Caller ID if available */
char cid_num[80];
char cid_name[80];
/* Hidden Caller ID (i.e. ANI) if appropriate */
char ani[80];
/* DNID */
char dnid[80];
/* Requested Extension */
char exten[AST_MAX_EXTENSION];
/* Expected Username */
char username[80];
/* Expected Secret */
char secret[80];
/* permitted authentication methods */
int authmethods;
Mark Spencer
committed
/* permitted encryption methods */
int encmethods;
/* MD5 challenge */
char challenge[10];
/* Public keys permitted keys for incoming authentication */
char inkeys[80];
/* Private key for outgoing authentication */
char outkey[80];
Mark Spencer
committed
/* Encryption AES-128 Key */
aes_encrypt_ctx ecx;
/* Decryption AES-128 Key */
aes_decrypt_ctx dcx;
/* 32 bytes of semi-random data */
char semirand[32];
char language[MAX_LANGUAGE];
/* Hostname/peername for naming purposes */
char host[80];
/* Associated registry */
struct iax2_registry *reg;
/* Associated peer for poking */
struct iax2_peer *peerpoke;
Mark Spencer
committed
/* Transferring status */
int transferring;
/* Transfer identifier */
int transferid;
/* Who we are IAX transfering to */
struct sockaddr_in transfer;
/* What's the new call number for the transfer */
unsigned short transfercallno;
Mark Spencer
committed
/* Transfer decrypt AES-128 Key */
aes_encrypt_ctx tdcx;
/* Status of knowledge of peer ADSI capability */
int peeradsicpe;
/* Who we are bridged to */
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 */
Mark Spencer
committed
int authid; /* Authentication rejection ID */
int initid; /* Initial peer auto-congest ID (based on qualified peers) */
int calling_ton;
int calling_tns;
int calling_pres;
char accountcode[AST_MAX_ACCOUNT_CODE];
int amaflags;
struct iax2_dpcache *dpentries;
/* last received remote rr */
struct iax_rr remote_rr;
/* Current base time: (just for stats) */
int min;
/* Dropped frame count: (just for stats) */
int frames_dropped;
/* received frame count: (just for stats) */
int frames_received;
};
static struct ast_iax2_queue {
struct iax_frame *head;
struct iax_frame *tail;
ast_mutex_t lock;
} iaxq;
static struct ast_user_list {
struct iax2_user *users;
ast_mutex_t lock;
} userl;
static struct ast_peer_list {
struct iax2_peer *peers;
ast_mutex_t lock;
static struct ast_firmware_list {
struct iax_firmware *wares;
ast_mutex_t lock;
} waresl;
/* Extension exists */
#define CACHE_FLAG_EXISTS (1 << 0)
/* Extension is nonexistent */
/* Extension can exist */
#define CACHE_FLAG_CANEXIST (1 << 2)
/* Waiting to hear back response */
#define CACHE_FLAG_PENDING (1 << 3)
/* Timed out */
#define CACHE_FLAG_TIMEOUT (1 << 4)
/* Request transmitted */
/* Timeout */
#define CACHE_FLAG_UNKNOWN (1 << 6)
/* Matchmore */
char peercontext[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
struct timeval orig;
struct timeval expirey;
int flags;
unsigned short callno;
int waiters[256];
struct iax2_dpcache *next;
struct iax2_dpcache *peer; /* For linking in peers */
} *dpcache;
Mark Spencer
committed
AST_MUTEX_DEFINE_STATIC(dpcache_lock);
Kevin P. Fleming
committed
static void reg_source_db(struct iax2_peer *p);
static struct iax2_peer *realtime_peer(const char *peername);
static void destroy_peer(struct iax2_peer *peer);
static int ast_cli_netstats(int fd, int limit_fmt);
static void iax_debug_output(const char *data)
static void iax_error_output(const char *data)
Mark Spencer
committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
#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];
Mark Spencer
committed
static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
static int send_command_locked(unsigned short callno, char, int, unsigned int, const char *, int, int);
static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int);
static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int);
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);
static int iax2_provision(struct sockaddr_in *end, 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);
Mark Spencer
committed
static int iax2_sendtext(struct ast_channel *c, const char *text);
static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
Mark Spencer
committed
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 int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
Mark Spencer
committed
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 = {
.type = channeltype,
.description = tdesc,
.capabilities = IAX_CAPABILITY_FULLBANDWIDTH,
Mark Spencer
committed
.properties = AST_CHAN_TP_WANTSJITTER,
.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,
};
static int send_ping(void *data)
{
int callno = (long)data;
/* Ping only if it's real, not if it's bridged */
if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
if (!iaxs[callno]->bridgecallno)
#endif
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
return 1;
} else
return 0;
}
Mark Spencer
committed
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;
}
static int send_lagrq(void *data)
{
int callno = (long)data;
/* Ping only if it's real not if it's bridged */
if (iaxs[callno]) {
#ifdef BRIDGE_OPTIMIZATION
if (!iaxs[callno]->bridgecallno)
#endif
send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
return 1;
} else
return 0;
}
static unsigned char compress_subclass(int subclass)
{
int x;
int power=-1;
/* If it's 128 or smaller, just return it */
return subclass;
/* Otherwise find its power */
if (subclass & (1 << x)) {
if (power > -1) {
ast_log(LOG_WARNING, "Can't compress subclass %d\n", subclass);
return 0;
} else
power = x;
}
}
}
static int uncompress_subclass(unsigned char csub)
{
/* If the SC_LOG flag is set, return 2^csub otherwise csub */
/* 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);
peer = realtime_peer(name);
return peer;
}
static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
{
struct iax2_peer *peer;
int res = 0;
if (lockpeer)
ast_mutex_lock(&peerl.lock);
peer = peerl.peers;
while(peer) {
if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
(peer->addr.sin_port == sin.sin_port)) {
Kevin P. Fleming
committed
ast_copy_string(host, peer->name, len);
res = 1;
break;
}
peer = peer->next;
}
if (lockpeer)
ast_mutex_unlock(&peerl.lock);
static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, const char *host)
{
struct chan_iax2_pvt *tmp;
tmp = malloc(sizeof(struct chan_iax2_pvt));
if (tmp) {
memset(tmp, 0, sizeof(struct chan_iax2_pvt));
tmp->prefs = prefs;
tmp->callno = 0;
tmp->peercallno = 0;
tmp->transfercallno = 0;
tmp->bridgecallno = 0;
tmp->pingid = -1;
tmp->lagid = -1;
tmp->autoid = -1;
Mark Spencer
committed
tmp->authid = -1;
Kevin P. Fleming
committed
/* ast_copy_string(tmp->context, context, sizeof(tmp->context)); */
ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
ast_copy_string(tmp->host, host, sizeof(tmp->host));
Mark Spencer
committed
#ifdef NEWJB
{
Mark Spencer
committed
tmp->jb = jb_new();
tmp->jbid = -1;
jbconf.max_jitterbuf = maxjitterbuffer;
jbconf.resync_threshold = resyncthreshold;
Kevin P. Fleming
committed
jbconf.max_contig_interp = maxjitterinterps;
jb_setconf(tmp->jb,&jbconf);
Mark Spencer
committed
}
#endif
static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
struct iax_frame *new = iax_frame_new(DIRECTION_INGRESS, fr->af.datalen);
memcpy(new, fr, sizeof(struct iax_frame));
iax_frame_wrap(new, &fr->af);
new->data = NULL;
new->datalen = 0;
new->direction = DIRECTION_INGRESS;
new->retrans = -1;
}
return new;
}
#define NEW_ALLOW 1
#define NEW_FORCE 2
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur)
{
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 == callno) ||
((dcallno == cur->callno) && !cur->peercallno)) {
/* 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)
return 1;
}
return 0;
}
static void update_max_trunk(void)
{
int max = TRUNK_CALL_START;
int x;
/* XXX Prolly don't need locks here XXX */
for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
if (iaxs[x])
max = x + 1;
}
maxtrunkcall = max;
if (option_debug)
ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
}
static void update_max_nontrunk(void)
{
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 (option_debug)
ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);
}
static int make_trunk(unsigned short callno, int locked)
{
int x;
int res= 0;
struct timeval now;
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;
}
gettimeofday(&now, NULL);
for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
ast_mutex_lock(&iaxsl[x]);
if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
iaxs[x] = iaxs[callno];
iaxs[x]->callno = x;
iaxs[callno] = NULL;
/* Update the two timers that should have been started */
if (iaxs[x]->pingid > -1)
ast_sched_del(sched, iaxs[x]->pingid);
if (iaxs[x]->lagid > -1)
ast_sched_del(sched, iaxs[x]->lagid);
iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
ast_mutex_unlock(&iaxsl[callno]);
ast_mutex_unlock(&iaxsl[x]);
ast_mutex_unlock(&iaxsl[x]);
ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
return -1;
}
ast_log(LOG_DEBUG, "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 find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd)